chef-11.8.2/0000755000004100000410000000000012254362222012540 5ustar www-datawww-datachef-11.8.2/Rakefile0000644000004100000410000001017112254362222014205 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008, 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require File.dirname(__FILE__) + '/lib/chef/version' require 'rubygems' require 'rubygems/package_task' require 'rdoc/task' require './tasks/rspec.rb' GEM_NAME = "chef" # This has to be here or else the docs get generated *after* the gem is created task :gem => 'docs:all' Dir[File.expand_path("../*gemspec", __FILE__)].reverse.each do |gemspec_path| gemspec = eval(IO.read(gemspec_path)) Gem::PackageTask.new(gemspec).define end begin require 'sdoc' Rake::RDocTask.new do |rdoc| rdoc.title = "Chef Ruby API Documentation" rdoc.main = "README.rdoc" rdoc.options << '--fmt' << 'shtml' # explictly set shtml generator rdoc.template = 'direct' # lighter template rdoc.rdoc_files.include("README.rdoc", "LICENSE", "spec/tiny_server.rb", "lib/**/*.rb") rdoc.rdoc_dir = "rdoc" end rescue LoadError puts "sdoc is not available. (sudo) gem install sdoc to generate rdoc documentation." rescue TypeError puts "sdoc is not working on ruby-2.0.0 and throwing an odd TypeError, rdoc generation will be disabled on ruby 2.0 until that gets fixed." end task :install => :package do sh %{gem install pkg/#{GEM_NAME}-#{Chef::VERSION}.gem --no-rdoc --no-ri} end task :uninstall do sh %{gem uninstall #{GEM_NAME} -x -v #{Chef::VERSION} } end desc "Build it, tag it and ship it" task :ship => :gem do sh("git tag #{Chef::VERSION}") sh("git push opscode --tags") Dir[File.expand_path("../pkg/*.gem", __FILE__)].reverse.each do |built_gem| sh("gem push #{built_gem}") end end RONN_OPTS = "--manual='Chef Manual' --organization='Chef #{Chef::VERSION}' --date='#{Time.new.strftime('%Y-%m-%d')}'" namespace :docs do desc "Regenerate HTML manual from markdown" task :html desc "Regenerate help topics from man pages" task :list do topics = Array.new Dir['distro/common/man/man1/*.1'].each do |man| topics << File.basename(man, '.1') end File.open('lib/chef/knife/help_topics.rb', 'w') do |f| f.puts "# Do not edit this file by hand" f.puts "# This file is autogenerated by the docs:list rake task from the available manpages\n\n" f.puts "HELP_TOPICS = #{topics.inspect}" end end # we can have ronn in the path, but not in the bundle, require both ronn_in_bundle = true begin require 'ronn' rescue LoadError ronn_in_bundle = false end if ronn_in_bundle && system('which ronn > /dev/null') ['distro/common/markdown/man1/*.mkd', 'distro/common/markdown/man8/*.mkd'].each do |dir| Dir[dir].each do |mkd| basename = File.basename(mkd, '.mkd') if dir =~ /man1/ htmlfile = "distro/common/html/#{basename}.1.html" elsif dir =~ /man8/ htmlfile = "distro/common/html/#{basename}.8.html" end file(htmlfile => [mkd, 'lib/chef/version.rb']) do sh "ronn -5 #{RONN_OPTS} --style=toc #{mkd} --pipe > #{htmlfile}" end task :html => htmlfile end end else puts "get with the program and install ronn" end task :all => [:list, :html] end task :docs => "docs:all" begin require 'yard' DOC_FILES = [ "README.rdoc", "LICENSE", "spec/tiny_server.rb", "lib/**/*.rb" ] namespace :yard do desc "Create YARD documentation" YARD::Rake::YardocTask.new(:html) do |t| t.files = DOC_FILES t.options = ['--format', 'html'] end end rescue LoadError puts "yard is not available. (sudo) gem install yard to generate yard documentation." end chef-11.8.2/bin/0000755000004100000410000000000012254362222013310 5ustar www-datawww-datachef-11.8.2/bin/chef-client0000755000004100000410000000160712254362222015423 0ustar www-datawww-data#!/usr/bin/env ruby # # ./chef-client - Run the chef client # # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'rubygems' $:.unshift(File.join(File.dirname(__FILE__), "..", "lib")) require 'chef' require 'chef/application/client' Chef::Application::Client.new.run chef-11.8.2/bin/chef-solo0000755000004100000410000000160712254362222015121 0ustar www-datawww-data#!/usr/bin/env ruby # # ./chef-solo - Run the chef client, in stand-alone mode # # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'rubygems' $:.unshift(File.join(File.dirname(__FILE__), "..", "lib")) require 'chef/application/solo' Chef::Application::Solo.new.run chef-11.8.2/bin/chef-service-manager0000755000004100000410000000262712254362222017220 0ustar www-datawww-data#!/usr/bin/env ruby # # ./chef-service-manager - Control chef-service on Windows platforms. # # Author:: Serdar Sutay (serdar@opscode.com) # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'rubygems' $:.unshift(File.join(File.dirname(__FILE__), "..", "lib")) require 'chef' require 'chef/application/windows_service_manager' if Chef::Platform.windows? chef_client_service = { :service_name => "chef-client", :service_display_name => "Chef Client Service", :service_description => "Runs Opscode Chef Client on regular, configurable intervals.", :service_file_path => File.expand_path(File.join(File.dirname(__FILE__), '../lib/chef/application/windows_service.rb')) } Chef::Application::WindowsServiceManager.new(chef_client_service).run else puts "chef-service-manager is only available on Windows platforms." end chef-11.8.2/bin/chef-shell0000755000004100000410000000213212254362222015246 0ustar www-datawww-data#!/usr/bin/env ruby # # ./chef-shell - Run the Chef REPL (Shell) # # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 # License:: Apache License, Version 2.0 # # 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. begin require "rubygems" rescue LoadError end require "irb" require "irb/completion" require 'irb/ext/save-history' $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))) require "chef/shell" # On Windows only, enable irb --noreadline because of input problems -- # See CHEF-3284. IRB.conf[:USE_READLINE] = false if Chef::Platform::windows? Shell.start chef-11.8.2/bin/knife0000755000004100000410000000160012254362222014327 0ustar www-datawww-data#!/usr/bin/env ruby # # ./knife - Chef CLI interface # # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'rubygems' $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))) require 'chef/application/knife' Chef::Application::Knife.new.run chef-11.8.2/bin/shef0000755000004100000410000000202112254362222014156 0ustar www-datawww-data#!/usr/bin/env ruby # # ./chef-shell - Run the Chef REPL (Shell) # # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 # License:: Apache License, Version 2.0 # # 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. begin require "rubygems" rescue LoadError end require "irb" require "irb/completion" require 'irb/ext/save-history' $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))) require "chef/shell" Chef::Log.warn("DEPRECATED: The 'shef' program is renamed to 'chef-shell'") Shell.start chef-11.8.2/bin/chef-apply0000755000004100000410000000160212254362222015265 0ustar www-datawww-data#!/usr/bin/env ruby # # ./chef-apply - Run a single chef recipe # # Author:: Bryan W. Berry () # Copyright:: Copyright (c) 2012 Bryan W. Berry # License:: Apache License, Version 2.0 # # 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. require 'rubygems' $:.unshift(File.join(File.dirname(__FILE__), "..", "lib")) require 'chef/application/apply' Chef::Application::Apply.new.run chef-11.8.2/spec/0000755000004100000410000000000012254362222013472 5ustar www-datawww-datachef-11.8.2/spec/data/0000755000004100000410000000000012254362222014403 5ustar www-datawww-datachef-11.8.2/spec/data/gems/0000755000004100000410000000000012254362222015336 5ustar www-datawww-datachef-11.8.2/spec/data/gems/chef-integration-test-0.1.0.gem0000644000004100000410000001700012254362222022663 0ustar www-datawww-datadata.tar.gz0000644000000000000000000001007300000000000013320 0ustar00wheelwheel00000000000000cJZmoG+#Zvd`?(# ȇL {FSU3=$-- Er^zz_]]]q}%k_?"~'??UpuoWTO7or'WF|춿mSLMםv;'Vmٳv;Ӽqg,M&W?ߩKr~?SonջL^|wd|.MikB'?Ӱ+]UjmtZl5n핮 7u!q&Sl\St9}uvїJ{UbP3Hx+jJ|ɻۑF;P)o6;gV58emwJwqx1rv[Nz7ǥRWꊅ,մ/V(>v{IF_^xYl]SeJ;?TkFocy^75 wmW"D׍c 64o# b;Ğsָ r -ok;Smr }$B];ֵ^|T w GZ 8ЁWvCbJ[|r{Z L"f)] 08⌏ oajlx4MDExZc3vik,qC@e)G霩}QOά38"8S6QAP9@W=%:dӔC%>1[,dR{$i"0ӈ11$[V [ D^! b!yF$ʧ,`צ^>,>&i) *025@ӌ̾C5V罕`M\`"@J66[ѓD%u)~[=>v?~OS6SYD5s9֌|Խg %<ƍ;wM瑕k>02.kFny-y4|0ViΦ{pz#[-VPca7pꦋ⤢J3I-ˋ+ZUHx]'0!PuM%FQ Pp5lkcZXc V[Ktn3v.([RtJgɂl=49} nGl(R`+[A 4JqM(iSOu2\_%x 8}}qg̦o#j^S-&[~0LXnN$7 Th\+nS;6xCmH\Oo6sM Y Ry- ,=l,!5g5r{,]&0 V'eSPd =g}H#5V+ߒcyIs(d{v)륦B+|2!-DMGF>ZUz;+ڡxSPň.*!]My#dI, ȟP"l#_qLhyTob( d˙5@eƋn}H=pyyapB6R=ǽڏ`R6tl?kcěeSBQ41$5I+apŶ~R *] .y"YMa8v[S0H„T}@ꄗ{#B5dMgZMk3-.{KK ^(ob Ct&Ş.}H#D&XaV@#I6+Ue1-u(qٞYud^@(0#),K\i8zO4BJhx+iv울 } >$aٍ=ܣ5iEQ` La~+ܶЄ(L]tGB:E[?(BV&,֍aQ/TR -߃" w5*gG,[)Y\r >K>磃iE:'V0 y^c0z|z?ະhd\rDܛEyt@XB aXiޅ<<4#gogq>ק7Brs ˨kf4s "Ty=<@ܬYA r+^H>-1SpXۙ;:d,{@bxb'!7Ʉfq0L=! iIKoȏ4`O/n~߱5yw_^\ϯmzb|Z]\s~} .b>l2Hp:;tln=Lz7Wl|}6~};WO/*Wwr}A^7\ܪn]IeP{,Az$,$l%j̛,B;ـPpރ.og\MnS 9h2=ԧ]FY%L\6syQO7z0x DJ?'x#{ '-s SCRO', :long => '--scro SCRO', :description => 'a configurable setting' attr_reader :ran def run @ran = true self # return self so tests can poke at me end end end chef-11.8.2/spec/data/knife_subcommand/test_name_mapping.rb0000644000004100000410000000010412254362222023721 0ustar www-datawww-datamodule KnifeSpecs class TestNameMapping < Chef::Knife end end chef-11.8.2/spec/data/knife_subcommand/test_explicit_category.rb0000644000004100000410000000035512254362222025014 0ustar www-datawww-datamodule KnifeSpecs class TestExplicitCategory < Chef::Knife # i.e., the cookbook site commands should be in the cookbook site # category instead of cookbook (which is what would be assumed) category "cookbook site" end endchef-11.8.2/spec/data/metadata/0000755000004100000410000000000012254362222016163 5ustar www-datawww-datachef-11.8.2/spec/data/metadata/quick_start/0000755000004100000410000000000012254362222020514 5ustar www-datawww-datachef-11.8.2/spec/data/metadata/quick_start/metadata.rb0000644000004100000410000000074112254362222022623 0ustar www-datawww-datamaintainer "Opscode, Inc." maintainer_email "cookbooks@opscode.com" license "Apache 2.0" description "Example cookbook for quick_start wiki document" version "0.7" %w{ redhat fedora centos ubuntu debian macosx freebsd openbsd solaris }.each do |os| supports os end attribute "quick_start/deep_thought", :display_name => "Quick Start Deep Thought", :description => "A deep thought", :default => "If a tree falls in the forest..." chef-11.8.2/spec/data/cb_version_cookbooks/0000755000004100000410000000000012254362222020605 5ustar www-datawww-datachef-11.8.2/spec/data/cb_version_cookbooks/tatft/0000755000004100000410000000000012254362222021727 5ustar www-datawww-datachef-11.8.2/spec/data/cb_version_cookbooks/tatft/definitions/0000755000004100000410000000000012254362222024242 5ustar www-datawww-datachef-11.8.2/spec/data/cb_version_cookbooks/tatft/definitions/runit_service.rb0000644000004100000410000000010012254362222027437 0ustar www-datawww-data# IRL the runit_service is a definition to set up runit serviceschef-11.8.2/spec/data/cb_version_cookbooks/tatft/files/0000755000004100000410000000000012254362222023031 5ustar www-datawww-datachef-11.8.2/spec/data/cb_version_cookbooks/tatft/files/default/0000755000004100000410000000000012254362222024455 5ustar www-datawww-datachef-11.8.2/spec/data/cb_version_cookbooks/tatft/files/default/giant_blob.tgz0000644000004100000410000000003312254362222027277 0ustar www-datawww-data# not really a giant blob #chef-11.8.2/spec/data/cb_version_cookbooks/tatft/resources/0000755000004100000410000000000012254362222023741 5ustar www-datawww-datachef-11.8.2/spec/data/cb_version_cookbooks/tatft/resources/lwr.rb0000644000004100000410000000001112254362222025062 0ustar www-datawww-data# a LWR #chef-11.8.2/spec/data/cb_version_cookbooks/tatft/templates/0000755000004100000410000000000012254362222023725 5ustar www-datawww-datachef-11.8.2/spec/data/cb_version_cookbooks/tatft/templates/default/0000755000004100000410000000000012254362222025351 5ustar www-datawww-datachef-11.8.2/spec/data/cb_version_cookbooks/tatft/templates/default/configuration.erb0000644000004100000410000000000012254362222030700 0ustar www-datawww-datachef-11.8.2/spec/data/cb_version_cookbooks/tatft/README.rdoc0000644000004100000410000000017612254362222023541 0ustar www-datawww-data= THIS RECIPE * is for testing CookbookLoader/CookbookVersion * has at least one of every kind of file that cookbooks can havechef-11.8.2/spec/data/cb_version_cookbooks/tatft/providers/0000755000004100000410000000000012254362222023744 5ustar www-datawww-datachef-11.8.2/spec/data/cb_version_cookbooks/tatft/providers/lwp.rb0000644000004100000410000000000712254362222025070 0ustar www-datawww-data# a LWPchef-11.8.2/spec/data/cb_version_cookbooks/tatft/attributes/0000755000004100000410000000000012254362222024115 5ustar www-datawww-datachef-11.8.2/spec/data/cb_version_cookbooks/tatft/attributes/default.rb0000644000004100000410000000004012254362222026060 0ustar www-datawww-data#one_of_each default attributes chef-11.8.2/spec/data/cb_version_cookbooks/tatft/libraries/0000755000004100000410000000000012254362222023703 5ustar www-datawww-datachef-11.8.2/spec/data/cb_version_cookbooks/tatft/libraries/ownage.rb0000644000004100000410000000001012254362222025477 0ustar www-datawww-data# 0wnagechef-11.8.2/spec/data/cb_version_cookbooks/tatft/recipes/0000755000004100000410000000000012254362222023361 5ustar www-datawww-datachef-11.8.2/spec/data/cb_version_cookbooks/tatft/recipes/default.rb0000644000004100000410000000002412254362222025326 0ustar www-datawww-data# the default recipechef-11.8.2/spec/data/kitchen/0000755000004100000410000000000012254362222016030 5ustar www-datawww-datachef-11.8.2/spec/data/kitchen/openldap/0000755000004100000410000000000012254362222017632 5ustar www-datawww-datachef-11.8.2/spec/data/kitchen/openldap/definitions/0000755000004100000410000000000012254362222022145 5ustar www-datawww-datachef-11.8.2/spec/data/kitchen/openldap/definitions/drewbarrymore.rb0000644000004100000410000000005312254362222025354 0ustar www-datawww-data# # Was in people magazine this month... #chef-11.8.2/spec/data/kitchen/openldap/definitions/client.rb0000644000004100000410000000002312254362222023743 0ustar www-datawww-data# # A sad client # chef-11.8.2/spec/data/kitchen/openldap/attributes/0000755000004100000410000000000012254362222022020 5ustar www-datawww-datachef-11.8.2/spec/data/kitchen/openldap/attributes/default.rb0000644000004100000410000000004612254362222023771 0ustar www-datawww-data# # Nothing to see here, move along # chef-11.8.2/spec/data/kitchen/openldap/attributes/robinson.rb0000644000004100000410000000002712254362222024175 0ustar www-datawww-data# # Smokey lives here #chef-11.8.2/spec/data/kitchen/openldap/recipes/0000755000004100000410000000000012254362222021264 5ustar www-datawww-datachef-11.8.2/spec/data/kitchen/openldap/recipes/gigantor.rb0000644000004100000410000000005012254362222023416 0ustar www-datawww-datacat "blanket" do pretty_kitty true endchef-11.8.2/spec/data/kitchen/openldap/recipes/woot.rb0000644000004100000410000000003212254362222022574 0ustar www-datawww-data# # Such a funny word.. # chef-11.8.2/spec/data/kitchen/openldap/recipes/ignoreme.rb0000644000004100000410000000004212254362222023412 0ustar www-datawww-data# # this file will never be seen #chef-11.8.2/spec/data/kitchen/chefignore0000644000004100000410000000021512254362222020062 0ustar www-datawww-data# # The ignore file allows you to skip files in cookbooks with the same name that appear # later in the search path. # recipes/ignoreme\.rb chef-11.8.2/spec/data/run_context/0000755000004100000410000000000012254362222016753 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/nodes/0000755000004100000410000000000012254362222020063 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/nodes/run_context.rb0000644000004100000410000000014112254362222022754 0ustar www-datawww-data## # Nodes should have a unique name ## name "compile" run_list "test", "test::one", "test::two" chef-11.8.2/spec/data/run_context/cookbooks/0000755000004100000410000000000012254362222020744 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/circular-dep1/0000755000004100000410000000000012254362222023377 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/circular-dep1/definitions/0000755000004100000410000000000012254362222025712 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/circular-dep1/definitions/circular_dep1_res.rb0000644000004100000410000000006412254362222031625 0ustar www-datawww-dataLibraryLoadOrder.record('circular-dep1-definition') chef-11.8.2/spec/data/run_context/cookbooks/circular-dep1/resources/0000755000004100000410000000000012254362222025411 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/circular-dep1/resources/resource.rb0000644000004100000410000000006212254362222027563 0ustar www-datawww-dataLibraryLoadOrder.record('circular-dep1-resource') chef-11.8.2/spec/data/run_context/cookbooks/circular-dep1/metadata.rb0000644000004100000410000000005512254362222025504 0ustar www-datawww-dataname "circular-dep1" depends "circular-dep2" chef-11.8.2/spec/data/run_context/cookbooks/circular-dep1/providers/0000755000004100000410000000000012254362222025414 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/circular-dep1/providers/provider.rb0000644000004100000410000000006212254362222027571 0ustar www-datawww-dataLibraryLoadOrder.record('circular-dep1-provider') chef-11.8.2/spec/data/run_context/cookbooks/circular-dep1/attributes/0000755000004100000410000000000012254362222025565 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/circular-dep1/attributes/default.rb0000644000004100000410000000012612254362222027535 0ustar www-datawww-dataset_unless[:attr_load_order] = [] set[:attr_load_order] << "circular-dep1::default" chef-11.8.2/spec/data/run_context/cookbooks/circular-dep1/libraries/0000755000004100000410000000000012254362222025353 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/circular-dep1/libraries/lib.rb0000644000004100000410000000005212254362222026443 0ustar www-datawww-dataLibraryLoadOrder.record("circular-dep1") chef-11.8.2/spec/data/run_context/cookbooks/circular-dep1/recipes/0000755000004100000410000000000012254362222025031 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/circular-dep1/recipes/default.rb0000644000004100000410000000000012254362222026770 0ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/no-default-attr/0000755000004100000410000000000012254362222023752 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/no-default-attr/definitions/0000755000004100000410000000000012254362222026265 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/no-default-attr/definitions/no_default-attr_res.rb0000644000004100000410000000006612254362222032555 0ustar www-datawww-dataLibraryLoadOrder.record('no-default-attr-definition') chef-11.8.2/spec/data/run_context/cookbooks/no-default-attr/resources/0000755000004100000410000000000012254362222025764 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/no-default-attr/resources/resource.rb0000644000004100000410000000006412254362222030140 0ustar www-datawww-dataLibraryLoadOrder.record('no-default-attr-resource') chef-11.8.2/spec/data/run_context/cookbooks/no-default-attr/providers/0000755000004100000410000000000012254362222025767 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/no-default-attr/providers/provider.rb0000644000004100000410000000006412254362222030146 0ustar www-datawww-dataLibraryLoadOrder.record('no-default-attr-provider') chef-11.8.2/spec/data/run_context/cookbooks/no-default-attr/attributes/0000755000004100000410000000000012254362222026140 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/no-default-attr/attributes/server.rb0000644000004100000410000000012612254362222027772 0ustar www-datawww-dataset_unless[:attr_load_order] = [] set[:attr_load_order] << "no-default-attr::server" chef-11.8.2/spec/data/run_context/cookbooks/no-default-attr/recipes/0000755000004100000410000000000012254362222025404 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/no-default-attr/recipes/default.rb0000644000004100000410000000000012254362222027343 0ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/dependency2/0000755000004100000410000000000012254362222023144 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/dependency2/definitions/0000755000004100000410000000000012254362222025457 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/dependency2/definitions/dependency2_res.rb0000644000004100000410000000006212254362222031053 0ustar www-datawww-dataLibraryLoadOrder.record('dependency2-definition') chef-11.8.2/spec/data/run_context/cookbooks/dependency2/resources/0000755000004100000410000000000012254362222025156 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/dependency2/resources/resource.rb0000644000004100000410000000006012254362222027326 0ustar www-datawww-dataLibraryLoadOrder.record('dependency2-resource') chef-11.8.2/spec/data/run_context/cookbooks/dependency2/providers/0000755000004100000410000000000012254362222025161 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/dependency2/providers/provider.rb0000644000004100000410000000006012254362222027334 0ustar www-datawww-dataLibraryLoadOrder.record('dependency2-provider') chef-11.8.2/spec/data/run_context/cookbooks/dependency2/attributes/0000755000004100000410000000000012254362222025332 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/dependency2/attributes/default.rb0000644000004100000410000000012312254362222027277 0ustar www-datawww-dataset_unless[:attr_load_order] = [] set[:attr_load_order] << "dependency2::default" chef-11.8.2/spec/data/run_context/cookbooks/dependency2/libraries/0000755000004100000410000000000012254362222025120 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/dependency2/libraries/lib.rb0000644000004100000410000000005012254362222026206 0ustar www-datawww-dataLibraryLoadOrder.record("dependency2") chef-11.8.2/spec/data/run_context/cookbooks/dependency2/recipes/0000755000004100000410000000000012254362222024576 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/dependency2/recipes/default.rb0000644000004100000410000000000012254362222026535 0ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test-with-deps/0000755000004100000410000000000012254362222023625 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test-with-deps/definitions/0000755000004100000410000000000012254362222026140 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test-with-deps/definitions/test_with-deps_res.rb0000644000004100000410000000006512254362222032302 0ustar www-datawww-dataLibraryLoadOrder.record('test-with-deps-definition') chef-11.8.2/spec/data/run_context/cookbooks/test-with-deps/resources/0000755000004100000410000000000012254362222025637 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test-with-deps/resources/resource.rb0000644000004100000410000000006312254362222030012 0ustar www-datawww-dataLibraryLoadOrder.record('test-with-deps-resource') chef-11.8.2/spec/data/run_context/cookbooks/test-with-deps/metadata.rb0000644000004100000410000000010212254362222025723 0ustar www-datawww-dataname "test-with-deps" depends "dependency1" depends "dependency2" chef-11.8.2/spec/data/run_context/cookbooks/test-with-deps/providers/0000755000004100000410000000000012254362222025642 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test-with-deps/providers/provider.rb0000644000004100000410000000006312254362222030020 0ustar www-datawww-dataLibraryLoadOrder.record('test-with-deps-provider') chef-11.8.2/spec/data/run_context/cookbooks/test-with-deps/attributes/0000755000004100000410000000000012254362222026013 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test-with-deps/attributes/default.rb0000644000004100000410000000012612254362222027763 0ustar www-datawww-dataset_unless[:attr_load_order] = [] set[:attr_load_order] << "test-with-deps::default" chef-11.8.2/spec/data/run_context/cookbooks/test-with-deps/libraries/0000755000004100000410000000000012254362222025601 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test-with-deps/libraries/lib.rb0000644000004100000410000000005212254362222026671 0ustar www-datawww-dataLibraryLoadOrder.record("test-with-deps") chef-11.8.2/spec/data/run_context/cookbooks/test-with-deps/recipes/0000755000004100000410000000000012254362222025257 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test-with-deps/recipes/default.rb0000644000004100000410000000000012254362222027216 0ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test-with-deps/recipes/server.rb0000644000004100000410000000000012254362222027100 0ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/dependency1/0000755000004100000410000000000012254362222023143 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/dependency1/definitions/0000755000004100000410000000000012254362222025456 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/dependency1/definitions/dependency1_res.rb0000644000004100000410000000006212254362222031051 0ustar www-datawww-dataLibraryLoadOrder.record('dependency1-definition') chef-11.8.2/spec/data/run_context/cookbooks/dependency1/resources/0000755000004100000410000000000012254362222025155 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/dependency1/resources/resource.rb0000644000004100000410000000006012254362222027325 0ustar www-datawww-dataLibraryLoadOrder.record('dependency1-resource') chef-11.8.2/spec/data/run_context/cookbooks/dependency1/providers/0000755000004100000410000000000012254362222025160 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/dependency1/providers/provider.rb0000644000004100000410000000006012254362222027333 0ustar www-datawww-dataLibraryLoadOrder.record('dependency1-provider') chef-11.8.2/spec/data/run_context/cookbooks/dependency1/attributes/0000755000004100000410000000000012254362222025331 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/dependency1/attributes/default.rb0000644000004100000410000000012212254362222027275 0ustar www-datawww-dataset_unless[:attr_load_order] = [] set[:attr_load_order] << "dependency1::default" chef-11.8.2/spec/data/run_context/cookbooks/dependency1/attributes/zz_last.rb0000644000004100000410000000012312254362222027340 0ustar www-datawww-dataset_unless[:attr_load_order] = [] set[:attr_load_order] << "dependency1::zz_last" chef-11.8.2/spec/data/run_context/cookbooks/dependency1/attributes/aa_first.rb0000644000004100000410000000012312254362222027442 0ustar www-datawww-dataset_unless[:attr_load_order] = [] set[:attr_load_order] << "dependency1::aa_first" chef-11.8.2/spec/data/run_context/cookbooks/dependency1/libraries/0000755000004100000410000000000012254362222025117 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/dependency1/libraries/lib.rb0000644000004100000410000000005012254362222026205 0ustar www-datawww-dataLibraryLoadOrder.record("dependency1") chef-11.8.2/spec/data/run_context/cookbooks/dependency1/recipes/0000755000004100000410000000000012254362222024575 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/dependency1/recipes/default.rb0000644000004100000410000000000012254362222026534 0ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test/0000755000004100000410000000000012254362222021723 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test/definitions/0000755000004100000410000000000012254362222024236 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test/definitions/new_cat.rb0000644000004100000410000000016212254362222026202 0ustar www-datawww-datadefine :new_cat, :is_pretty => true do cat "#{params[:name]}" do pretty_kitty params[:is_pretty] end end chef-11.8.2/spec/data/run_context/cookbooks/test/definitions/new_animals.rb0000644000004100000410000000023412254362222027057 0ustar www-datawww-datadefine :new_dog, :is_cute => true do dog "#{params[:name]}" do cute params[:is_cute] end end define :new_badger do badger "#{params[:name]}" end chef-11.8.2/spec/data/run_context/cookbooks/test/definitions/test_res.rb0000644000004100000410000000005312254362222026411 0ustar www-datawww-dataLibraryLoadOrder.record('test-definition') chef-11.8.2/spec/data/run_context/cookbooks/test/resources/0000755000004100000410000000000012254362222023735 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test/resources/resource.rb0000644000004100000410000000005112254362222026105 0ustar www-datawww-dataLibraryLoadOrder.record('test-resource') chef-11.8.2/spec/data/run_context/cookbooks/test/providers/0000755000004100000410000000000012254362222023740 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test/providers/provider.rb0000644000004100000410000000005112254362222026113 0ustar www-datawww-dataLibraryLoadOrder.record('test-provider') chef-11.8.2/spec/data/run_context/cookbooks/test/attributes/0000755000004100000410000000000012254362222024111 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test/attributes/default.rb0000644000004100000410000000000012254362222026050 0ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test/attributes/george.rb0000644000004100000410000000004012254362222025700 0ustar www-datawww-datadefault[:george] = "washington" chef-11.8.2/spec/data/run_context/cookbooks/test/recipes/0000755000004100000410000000000012254362222023355 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test/recipes/default.rb0000644000004100000410000000005412254362222025325 0ustar www-datawww-data cat "einstein" do pretty_kitty true end chef-11.8.2/spec/data/run_context/cookbooks/test/recipes/two.rb0000644000004100000410000000013212254362222024507 0ustar www-datawww-datacat "peanut" do pretty_kitty true end new_cat "fat peanut" do pretty_kitty false end chef-11.8.2/spec/data/run_context/cookbooks/test/recipes/one.rb0000644000004100000410000000013012254362222024455 0ustar www-datawww-datacat "loulou" do pretty_kitty true end new_cat "birthday" do pretty_kitty false end chef-11.8.2/spec/data/run_context/cookbooks/test-with-circular-deps/0000755000004100000410000000000012254362222025427 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test-with-circular-deps/definitions/0000755000004100000410000000000012254362222027742 5ustar www-datawww-data././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootchef-11.8.2/spec/data/run_context/cookbooks/test-with-circular-deps/definitions/test_with-circular-deps_res.rbchef-11.8.2/spec/data/run_context/cookbooks/test-with-circular-deps/definitions/test_with-circular-d0000644000004100000410000000007612254362222033725 0ustar www-datawww-dataLibraryLoadOrder.record('test-with-circular-deps-definition') chef-11.8.2/spec/data/run_context/cookbooks/test-with-circular-deps/resources/0000755000004100000410000000000012254362222027441 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test-with-circular-deps/resources/resource.rb0000644000004100000410000000007412254362222031616 0ustar www-datawww-dataLibraryLoadOrder.record('test-with-circular-deps-resource') chef-11.8.2/spec/data/run_context/cookbooks/test-with-circular-deps/metadata.rb0000644000004100000410000000006712254362222027537 0ustar www-datawww-dataname "test-with-circular-deps" depends "circular-dep1" chef-11.8.2/spec/data/run_context/cookbooks/test-with-circular-deps/providers/0000755000004100000410000000000012254362222027444 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test-with-circular-deps/providers/provider.rb0000644000004100000410000000007412254362222031624 0ustar www-datawww-dataLibraryLoadOrder.record('test-with-circular-deps-provider') chef-11.8.2/spec/data/run_context/cookbooks/test-with-circular-deps/attributes/0000755000004100000410000000000012254362222027615 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test-with-circular-deps/attributes/default.rb0000644000004100000410000000013712254362222031567 0ustar www-datawww-dataset_unless[:attr_load_order] = [] set[:attr_load_order] << "test-with-circular-deps::default" chef-11.8.2/spec/data/run_context/cookbooks/test-with-circular-deps/libraries/0000755000004100000410000000000012254362222027403 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test-with-circular-deps/libraries/lib.rb0000644000004100000410000000006412254362222030476 0ustar www-datawww-dataLibraryLoadOrder.record("test-with-circular-deps") chef-11.8.2/spec/data/run_context/cookbooks/test-with-circular-deps/recipes/0000755000004100000410000000000012254362222027061 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/test-with-circular-deps/recipes/default.rb0000644000004100000410000000000012254362222031020 0ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/circular-dep2/0000755000004100000410000000000012254362222023400 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/circular-dep2/definitions/0000755000004100000410000000000012254362222025713 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/circular-dep2/definitions/circular_dep2_res.rb0000644000004100000410000000006412254362222031627 0ustar www-datawww-dataLibraryLoadOrder.record('circular-dep2-definition') chef-11.8.2/spec/data/run_context/cookbooks/circular-dep2/resources/0000755000004100000410000000000012254362222025412 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/circular-dep2/resources/resource.rb0000644000004100000410000000006212254362222027564 0ustar www-datawww-dataLibraryLoadOrder.record('circular-dep2-resource') chef-11.8.2/spec/data/run_context/cookbooks/circular-dep2/metadata.rb0000644000004100000410000000005512254362222025505 0ustar www-datawww-dataname "circular-dep2" depends "circular-dep1" chef-11.8.2/spec/data/run_context/cookbooks/circular-dep2/providers/0000755000004100000410000000000012254362222025415 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/circular-dep2/providers/provider.rb0000644000004100000410000000006212254362222027572 0ustar www-datawww-dataLibraryLoadOrder.record('circular-dep2-provider') chef-11.8.2/spec/data/run_context/cookbooks/circular-dep2/attributes/0000755000004100000410000000000012254362222025566 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/circular-dep2/attributes/default.rb0000644000004100000410000000012512254362222027535 0ustar www-datawww-dataset_unless[:attr_load_order] = [] set[:attr_load_order] << "circular-dep2::default" chef-11.8.2/spec/data/run_context/cookbooks/circular-dep2/libraries/0000755000004100000410000000000012254362222025354 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/circular-dep2/libraries/lib.rb0000644000004100000410000000005212254362222026444 0ustar www-datawww-dataLibraryLoadOrder.record("circular-dep2") chef-11.8.2/spec/data/run_context/cookbooks/circular-dep2/recipes/0000755000004100000410000000000012254362222025032 5ustar www-datawww-datachef-11.8.2/spec/data/run_context/cookbooks/circular-dep2/recipes/default.rb0000644000004100000410000000000012254362222026771 0ustar www-datawww-datachef-11.8.2/spec/data/definitions/0000755000004100000410000000000012254362222016716 5ustar www-datawww-datachef-11.8.2/spec/data/definitions/test.rb0000644000004100000410000000015212254362222020220 0ustar www-datawww-datadefine :rico_suave, :rich => "smooth" do zen_master "test" do something "#{params[:rich]}" end endchef-11.8.2/spec/data/lwrp_override/0000755000004100000410000000000012254362222017266 5ustar www-datawww-datachef-11.8.2/spec/data/lwrp_override/resources/0000755000004100000410000000000012254362222021300 5ustar www-datawww-datachef-11.8.2/spec/data/lwrp_override/resources/foo.rb0000644000004100000410000000015212254362222022406 0ustar www-datawww-dataactions :prepare_thumbs, :twiddle_thumbs default_action :pass_buck attribute :monkey, :kind_of => String chef-11.8.2/spec/data/lwrp_override/providers/0000755000004100000410000000000012254362222021303 5ustar www-datawww-datachef-11.8.2/spec/data/lwrp_override/providers/buck_passer.rb0000644000004100000410000000033412254362222024131 0ustar www-datawww-dataaction :pass_buck do lwrp_foo :prepared_thumbs do action :prepare_thumbs provider :lwrp_thumb_twiddler end lwrp_foo :twiddled_thumbs do action :twiddle_thumbs provider :lwrp_thumb_twiddler end endchef-11.8.2/spec/data/big_json.json0000644000004100000410000000454712254362222017102 0ustar www-datawww-data{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":"test" }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}chef-11.8.2/spec/data/shef-config.rb0000644000004100000410000000170512254362222017123 0ustar www-datawww-dataOhai::Config[:disabled_plugins] << 'darwin::system_profiler' << 'darwin::kernel' << 'darwin::ssh_host_key' << 'network_listeners' Ohai::Config[:disabled_plugins] << "virtualization" << "darwin::virtualization" Ohai::Config[:disabled_plugins] << 'darwin::uptime' << 'darwin::filesystem' << 'dmi' << 'lanuages' << 'perl' << 'python' << 'java' Ohai::Config[:disabled_plugins] << "linux::block_device" << "linux::kernel" << "linux::ssh_host_key" << "linux::virtualization" Ohai::Config[:disabled_plugins] << "linux::cpu" << "linux::memory" << "ec2" << "rackspace" << "eucalyptus" << "ip_scopes" Ohai::Config[:disabled_plugins] << "solaris2::cpu" << "solaris2::dmi" << "solaris2::filesystem" << "solaris2::kernel" Ohai::Config[:disabled_plugins] << "solaris2::virtualization" << "solaris2::zpools" Ohai::Config[:disabled_plugins] << 'c' << 'php' << 'mono' << 'groovy' << 'lua' << 'erlang' Ohai::Config[:disabled_plugins] << "kernel" << "linux::filesystem" << "ruby" chef-11.8.2/spec/data/ssl/0000755000004100000410000000000012254362222015204 5ustar www-datawww-datachef-11.8.2/spec/data/ssl/5e707473.00000644000004100000410000000205612254362222016275 0ustar www-datawww-data-----BEGIN CERTIFICATE----- MIIC6DCCAlGgAwIBAgIJANlevg7kzqvpMA0GCSqGSIb3DQEBBQUAMFcxITAfBgNV BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEeMBwGA1UECxMVU25ha2VvaWwg Q2VydGlmaWNhdGVzMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMDkxMjE5MTkxODUy WhcNMTAwMTE4MTkxODUyWjBXMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0 eSBMdGQxHjAcBgNVBAsTFVNuYWtlb2lsIENlcnRpZmljYXRlczESMBAGA1UEAxMJ bG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhm9En1DL3aC4H j5/SA6FXm6B/0AoVzoPfWX2rpkRcz/XX24JEhQhLXStjhDr4p/IrARnZ8shy0MA4 wNpNPEn5c0RvqKypHzX+AeQkBx8J1/8vnMAoM9b/4pd0FqgRW1UbhvqQDzkWmVyK Tz5yCiTntxDzudAtHlTo8V6E7UEDkwIDAQABo4G7MIG4MB0GA1UdDgQWBBTmAcyA CqQblJ1L4sOIzmkdIAtY6jCBiAYDVR0jBIGAMH6AFOYBzIAKpBuUnUviw4jOaR0g C1jqoVukWTBXMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxHjAc BgNVBAsTFVNuYWtlb2lsIENlcnRpZmljYXRlczESMBAGA1UEAxMJbG9jYWxob3N0 ggkA2V6+DuTOq+kwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQBe4f9R s0g5GCFekabzl9AHvIn4ITxenvuyaNX9f2BJbdgoD03wlGycBxjbC57RjFVfetu7 mtUYuJSx7iojBSC+LzotGptrG9d2BxrWOKBfF2K+dyoIG8kZL5aLfS0be6Cc5O3c L/IPadJhBu/EfyGI2vL1l8GspXdOxaFzHprpgA== -----END CERTIFICATE----- chef-11.8.2/spec/data/ssl/private_key_with_whitespace.pem0000644000004100000410000000322412254362222023501 0ustar www-datawww-data -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA49TA0y81ps0zxkOpmf5V4/c4IeR5yVyQFpX3JpxO4TquwnRh 8VSUhrw8kkTLmB3cS39Db+3HadvhoqCEbqPE6915kXSuk/cWIcNozujLK7tkuPEy YVsyTioQAddSdfe+8EhQVf3oHxaKmUd6waXrWqYCnhxgOjxocenREYNhZ/OETIei PbOku47vB4nJK/0GhKBytL2XnsRgfKgDxf42BqAi1jglIdeq8lAWZNF9TbNBU21A O1iuT7Pm6LyQujhggPznR5FJhXKRUARXBJZawxpGV4dGtdcahwXNE4601aXPra+x PcRd2puCNoEDBzgVuTSsLYeKBDMSfs173W1QYwIDAQABAoIBAGF05q7vqOGbMaSD 2Q7YbuE/JTHKTBZIlBI1QC2x+0P5GDxyEFttNMOVzcs7xmNhkpRw8eX1LrInrpMk WsIBKAFFEfWYlf0RWtRChJjNl+szE9jQxB5FJnWtJH/FHa78tR6PsF24aQyzVcJP g0FGujBihwgfV0JSCNOBkz8MliQihjQA2i8PGGmo4R4RVzGfxYKTIq9vvRq/+QEa Q4lpVLoBqnENpnY/9PTl6JMMjW2b0spbLjOPVwDaIzXJ0dChjNXo15K5SHI5mALJ I5gN7ODGb8PKUf4619ez194FXq+eob5YJdilTFKensIUvt3YhP1ilGMM+Chi5Vi/ /RCTw3ECgYEA9jTw4wv9pCswZ9wbzTaBj9yZS3YXspGg26y6Ohq3ZmvHz4jlT6uR xK+DDcUiK4072gci8S4Np0fIVS7q6ivqcOdzXPrTF5/j+MufS32UrBbUTPiM1yoO ECcy+1szl/KoLEV09bghPbvC58PFSXV71evkaTETYnA/F6RK12lEepcCgYEA7OSy bsMrGDVU/MKJtwqyGP9ubA53BorM4Pp9VVVSCrGGVhb9G/XNsjO5wJC8J30QAo4A s59ZzCpyNRy046AB8jwRQuSwEQbejSdeNgQGXhZ7aIVUtuDeFFdaIz/zjVgxsfj4 DPOuzieMmJ2MLR4F71ocboxNoDI7xruPSE8dDhUCgYA3vx732cQxgtHwAkeNPJUz dLiE/JU7CnxIoSB9fYUfPLI+THnXgzp7NV5QJN2qzMzLfigsQcg3oyo6F2h7Yzwv GkjlualIRRzCPaCw4Btkp7qkPvbs1QngIHALt8fD1N69P3DPHkTwjG4COjKWgnJq qoHKS6Fe/ZlbigikI6KsuwKBgQCTlSLoyGRHr6oj0hqz01EDK9ciMJzMkZp0Kvn8 OKxlBxYW+jlzut4MQBdgNYtS2qInxUoAnaz2+hauqhSzntK3k955GznpUatCqx0R b857vWviwPX2/P6+E3GPdl8IVsKXCvGWOBZWTuNTjQtwbDzsUepWoMgXnlQJSn5I YSlLxQKBgQD16Gw9kajpKlzsPa6XoQeGmZALT6aKWJQlrKtUQIrsIWM0Z6eFtX12 2jjHZ0awuCQ4ldqwl8IfRogWMBkHOXjTPVK0YKWWlxMpD/5+bGPARa5fir8O1Zpo Y6S6MeZ69Rp89ma4ttMZ+kwi1+XyHqC/dlcVRW42Zl5Dc7BALRlJjQ== -----END RSA PRIVATE KEY----- chef-11.8.2/spec/data/ssl/key.pem0000644000004100000410000000156712254362222016510 0ustar www-datawww-data-----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQDhm9En1DL3aC4Hj5/SA6FXm6B/0AoVzoPfWX2rpkRcz/XX24JE hQhLXStjhDr4p/IrARnZ8shy0MA4wNpNPEn5c0RvqKypHzX+AeQkBx8J1/8vnMAo M9b/4pd0FqgRW1UbhvqQDzkWmVyKTz5yCiTntxDzudAtHlTo8V6E7UEDkwIDAQAB AoGAGicC1tgdVFqqQ0wd3a14DXzH3SkTkjWPSdvI2pX6hLvCptQWRLUbIglZ1z5j y6FETEHjakVfgRe7wJhyddOQS3eeVt/aK0xBHz/JiJuIF+NzbJT9t01nPV21abYU lWIhWV8Ja39a5LKV6hee0TTYdAub7BVQ95kwrqMqRcDoXHECQQDxpAgq925Cmlz1 0Q1WZq2A/o8oqPvPS1FulPK2OgyOyQSK+DdcK2xUKGWMn0m9fDLLzj/pe/H3dN1I b8Z/iiWrAkEA7wPlesZX3GzfqQLd6GYGBa4IdrV5dHdeoCCVRnkFr06KjcqpAhg1 7i0T9frSC5EfRCfbGNgo4eutT9+D7HJhuQJAZeDBrNPbQetxDBbSp73sovkwhHUS jah0scnMtvWse7rW1nymYo7QQn8xqWMzJNerVvAjVB50ut8juLmfmAA3twJAQy9/ NBHI5Mcd365Unlz/WF1hN60vZNOhH7XJADRIqsyTGeRbuaEAl+DH+Z71qBa1CT2C 0usAIvFSmF8mADLu0QJAHSSh6zLNInvkhDjYAmEu3oeFQgQ4Rp7oiMaBZ6VVuOMo 4GU9CA18iI75NaO7FOfquJPkIJ0li0xadVofUpaJcg== -----END RSA PRIVATE KEY----- chef-11.8.2/spec/data/ssl/private_key.pem0000644000004100000410000000321712254362222020234 0ustar www-datawww-data-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA49TA0y81ps0zxkOpmf5V4/c4IeR5yVyQFpX3JpxO4TquwnRh 8VSUhrw8kkTLmB3cS39Db+3HadvhoqCEbqPE6915kXSuk/cWIcNozujLK7tkuPEy YVsyTioQAddSdfe+8EhQVf3oHxaKmUd6waXrWqYCnhxgOjxocenREYNhZ/OETIei PbOku47vB4nJK/0GhKBytL2XnsRgfKgDxf42BqAi1jglIdeq8lAWZNF9TbNBU21A O1iuT7Pm6LyQujhggPznR5FJhXKRUARXBJZawxpGV4dGtdcahwXNE4601aXPra+x PcRd2puCNoEDBzgVuTSsLYeKBDMSfs173W1QYwIDAQABAoIBAGF05q7vqOGbMaSD 2Q7YbuE/JTHKTBZIlBI1QC2x+0P5GDxyEFttNMOVzcs7xmNhkpRw8eX1LrInrpMk WsIBKAFFEfWYlf0RWtRChJjNl+szE9jQxB5FJnWtJH/FHa78tR6PsF24aQyzVcJP g0FGujBihwgfV0JSCNOBkz8MliQihjQA2i8PGGmo4R4RVzGfxYKTIq9vvRq/+QEa Q4lpVLoBqnENpnY/9PTl6JMMjW2b0spbLjOPVwDaIzXJ0dChjNXo15K5SHI5mALJ I5gN7ODGb8PKUf4619ez194FXq+eob5YJdilTFKensIUvt3YhP1ilGMM+Chi5Vi/ /RCTw3ECgYEA9jTw4wv9pCswZ9wbzTaBj9yZS3YXspGg26y6Ohq3ZmvHz4jlT6uR xK+DDcUiK4072gci8S4Np0fIVS7q6ivqcOdzXPrTF5/j+MufS32UrBbUTPiM1yoO ECcy+1szl/KoLEV09bghPbvC58PFSXV71evkaTETYnA/F6RK12lEepcCgYEA7OSy bsMrGDVU/MKJtwqyGP9ubA53BorM4Pp9VVVSCrGGVhb9G/XNsjO5wJC8J30QAo4A s59ZzCpyNRy046AB8jwRQuSwEQbejSdeNgQGXhZ7aIVUtuDeFFdaIz/zjVgxsfj4 DPOuzieMmJ2MLR4F71ocboxNoDI7xruPSE8dDhUCgYA3vx732cQxgtHwAkeNPJUz dLiE/JU7CnxIoSB9fYUfPLI+THnXgzp7NV5QJN2qzMzLfigsQcg3oyo6F2h7Yzwv GkjlualIRRzCPaCw4Btkp7qkPvbs1QngIHALt8fD1N69P3DPHkTwjG4COjKWgnJq qoHKS6Fe/ZlbigikI6KsuwKBgQCTlSLoyGRHr6oj0hqz01EDK9ciMJzMkZp0Kvn8 OKxlBxYW+jlzut4MQBdgNYtS2qInxUoAnaz2+hauqhSzntK3k955GznpUatCqx0R b857vWviwPX2/P6+E3GPdl8IVsKXCvGWOBZWTuNTjQtwbDzsUepWoMgXnlQJSn5I YSlLxQKBgQD16Gw9kajpKlzsPa6XoQeGmZALT6aKWJQlrKtUQIrsIWM0Z6eFtX12 2jjHZ0awuCQ4ldqwl8IfRogWMBkHOXjTPVK0YKWWlxMpD/5+bGPARa5fir8O1Zpo Y6S6MeZ69Rp89ma4ttMZ+kwi1+XyHqC/dlcVRW42Zl5Dc7BALRlJjQ== -----END RSA PRIVATE KEY----- chef-11.8.2/spec/data/ssl/chef-rspec.cert0000644000004100000410000000315712254362222020110 0ustar www-datawww-data-----BEGIN CERTIFICATE----- MIIEkjCCA3qgAwIBAgIJAKBJr4wSRUVvMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYD VQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHU2VhdHRsZTEN MAsGA1UEChMEQ2hlZjETMBEGA1UECxMKZGV2ZWxvcGVyczESMBAGA1UEAxMJa2Fs bGlzdGVjMR4wHAYJKoZIhvcNAQkBFg9kYW5Ab3BzY29kZS5jb20wHhcNMTAwNDEw MTkxMTMxWhcNMjAwNDA3MTkxMTMxWjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAgT Cldhc2hpbmd0b24xEDAOBgNVBAcTB1NlYXR0bGUxDTALBgNVBAoTBENoZWYxEzAR BgNVBAsTCmRldmVsb3BlcnMxEjAQBgNVBAMTCWthbGxpc3RlYzEeMBwGCSqGSIb3 DQEJARYPZGFuQG9wc2NvZGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAw5l9EtBHsJrb5AIxARP695an3v+509gOXRKnjWIRnU+knbdTnEdjlGGG SxuFR7Fnp2OM8ed7iPIKSrcM0vQ+g7vYKCv5Z8UR3sbLY8UHm9AgZ/bLAHEHS2if 1WHPD5DOe1B7HwW0IfEiW4/WakkVn4uoWw5rCZ87f4YCrETomXIo1n/rMFHf+yoY guuEfGQxRcQdlEZM9YMlMByQvXlVR5IVhpiMHBCyV6KzxjZVCgTlvS8nPMiiHpoO pgB6BGEQ/nn4Kapk40baPqpT4EP/DnBnbhhR3kBQ6MQRlh7bl5vjH5xFSFwGUUA9 IcaDTwfliD27bo36aMvcBhrsmbSwqwIDAQABo4H0MIHxMB0GA1UdDgQWBBS88Zxt vG+FTu1U+VFA47ffzwStbjCBwQYDVR0jBIG5MIG2gBS88ZxtvG+FTu1U+VFA47ff zwStbqGBkqSBjzCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x EDAOBgNVBAcTB1NlYXR0bGUxDTALBgNVBAoTBENoZWYxEzARBgNVBAsTCmRldmVs b3BlcnMxEjAQBgNVBAMTCWthbGxpc3RlYzEeMBwGCSqGSIb3DQEJARYPZGFuQG9w c2NvZGUuY29tggkAoEmvjBJFRW8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUF AAOCAQEAwwMrbuJAhP5uawJi5OYEaJKSbJGyahCcOAl4+ONgsdDoCy/9AZKzuFNc C8vM/Ee6jyugrKMdckvZ883kJ4770HU6nbomCUVKMHMzJBE1Guvsn8wZP3nKyeSZ eXXbH1b/NfstNyo6XLucaBRQvyvQYDUnk6osrBh+Gekvqsahr0wkVa8VUY2UySyY 60lYt4O92XJ1jWtYoFjRxeeUgo5E0TfIWj74kXhdMqwMf4Iv9VatfYR87ps5VMdf Hp+nrCRaquDAs87LdO9e7M8l+W1ryPfP2inuGjIozsN5lLmwBdT+O6NkpmuxGPEG ArIbYatR7+4MsDn+CjfkYblnmGLuug== -----END CERTIFICATE----- chef-11.8.2/spec/data/ssl/chef-rspec.key0000644000004100000410000000321312254362222017734 0ustar www-datawww-data-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAw5l9EtBHsJrb5AIxARP695an3v+509gOXRKnjWIRnU+knbdT nEdjlGGGSxuFR7Fnp2OM8ed7iPIKSrcM0vQ+g7vYKCv5Z8UR3sbLY8UHm9AgZ/bL AHEHS2if1WHPD5DOe1B7HwW0IfEiW4/WakkVn4uoWw5rCZ87f4YCrETomXIo1n/r MFHf+yoYguuEfGQxRcQdlEZM9YMlMByQvXlVR5IVhpiMHBCyV6KzxjZVCgTlvS8n PMiiHpoOpgB6BGEQ/nn4Kapk40baPqpT4EP/DnBnbhhR3kBQ6MQRlh7bl5vjH5xF SFwGUUA9IcaDTwfliD27bo36aMvcBhrsmbSwqwIDAQABAoIBAQC+hddKaA4se+sL 4QaSoj+mwtypXjZHnv/+sJj8IjY+IMGbzmJmqzLX6VbB+gCMoMTySwmS54NxFTHp LPwUz0vFTUdzecHpzg9mDAU5HUYYA1ZNbhq2R2JvlW16j1b9NnOpse77fLbFCPgK b8TOqnmheot2hkjEipGN2Z7o5gYaz1/3PtolkP1ypCTG6Bh7V3ohBLBIEdjA552o HNGe3t6PpvoNtBqaeb/j/SAOvg+8DGF1WQtE+5Y1koSlhABYWkHzHC1fHAzRMSHH ZMfKOQNusRgBRNJabdVqkuTbvyRCQEb2YGQxPPYV2C+AxAlh3APeYTg90vUqAq/3 ivNdilcBAoGBAOLELc0mcTftDbIMWVnrzAGAJOCMz3FkwGcV8nqNeA3R77e3pWL2 5+bKadWQGjjpR3ZEYt/RxHsoGCW3NtM44icxqVCTPW/unp2xqadjuvcsKrxk+1wD OdvVrwcd/N+KzgXO+Hm7xbV/loFms3ueGfCRbOueQyP4dj9MyOBGlO2hAoGBANzQ u8IrZBG0DL8YFdmjw4YWUENIOtABPU1qHo/sugTQjI9K3/E3LA7aaGnl2P//1tao SR/aP/To90H6D989/JomhkEKKA+DyL1sRL1NMdtWwrKdEq32W8fUN0JEA+Q1FMsd Hk6Ix+KrZVg9cTb9HoGikDxeHW3pPKDWaEkWIQLLAoGAD13N4L3/JBQLPop5r487 9soRNao1EHEMXK/vC4D0prMYNHHcYjVrB4el3lPygvLD5e7CaHpVfyb7Y+rjazLK mG9UEuK3YhNgaj00yuQGMmOqzbNmGRka3ZvATZIppZhJV7lruwwPXLo1n7Uu6myP Q28HW3wQ/qoCkU2JuzDtPKECgYBUrYcTEuixEUbCEU5vw6k7RltJMe27zn3frg5C Sxmatw7v9Fqkee/fUkowMgBhS47rimVgXaWhGaWYG3jytyajRpq9XlO2f2b/nQFP RscTwdWwASQkqhDQNMVsGAEWBnUO3v+8Rh/BANFAYW+FEtQcCmcdf0nx2DtzwkUD ogTOuQKBgCbEg+/ND/p8xKwY9LtjLKnrQSL5tSH/7prhLJvVVdW7FMRfKSp1t2xc kfJFqO1Lcf2j7hiclval3xDoWUretNQ5379T0Ob30WuIomSfeqcxJjCUtyN3fUqr z/QG9dk/23OOYJhRgAmttBDqpk5uB5mOQgSftdELNyw0EOyNIBfZ -----END RSA PRIVATE KEY----- chef-11.8.2/spec/data/templates/0000755000004100000410000000000012254362222016401 5ustar www-datawww-datachef-11.8.2/spec/data/templates/seattle.txt0000644000004100000410000000011012254362222020573 0ustar www-datawww-dataSeattle is a great town. Next time you visit, you should buy me a beer.chef-11.8.2/spec/data/nodes/0000755000004100000410000000000012254362222015513 5ustar www-datawww-datachef-11.8.2/spec/data/nodes/default.rb0000644000004100000410000000040312254362222017461 0ustar www-datawww-data## # Nodes should have a unique name ## name "test.example.com-default" ## # Nodes can set arbitrary arguments ## default[:sunshine] = "in" default[:something] = "else" ## # Nodes should have recipes ## run_list "operations-master", "operations-monitoring" chef-11.8.2/spec/data/nodes/test.example.com.rb0000644000004100000410000000042112254362222021223 0ustar www-datawww-data## # Nodes should have a unique name ## name "test.example.com" ## # Nodes can set arbitrary arguments ## normal[:sunshine] = "in" normal[:something] = "else" ## # Nodes should have recipes ## run_list "operations-master", "operations-monitoring" chef_environment "dev" chef-11.8.2/spec/data/nodes/test.rb0000644000004100000410000000040112254362222017012 0ustar www-datawww-data## # Nodes should have a unique name ## name "test.example.com-short" ## # Nodes can set arbitrary arguments ## default[:sunshine] = "in" default[:something] = "else" ## # Nodes should have recipes ## run_list "operations-master", "operations-monitoring" chef-11.8.2/spec/data/bootstrap/0000755000004100000410000000000012254362222016420 5ustar www-datawww-datachef-11.8.2/spec/data/bootstrap/secret.erb0000644000004100000410000000033212254362222020375 0ustar www-datawww-databash -c ' <% if encrypted_data_bag_secret -%> awk NF > /etc/chef/encrypted_data_bag_secret <<'EOP' <%= encrypted_data_bag_secret %> EOP chmod 0600 /etc/chef/encrypted_data_bag_secret <% end -%> <%= config_content %>' chef-11.8.2/spec/data/bootstrap/no_proxy.erb0000644000004100000410000000004112254362222020762 0ustar www-datawww-databash -c ' <%= config_content %>' chef-11.8.2/spec/data/bootstrap/encrypted_data_bag_secret0000644000004100000410000000002612254362222023505 0ustar www-datawww-datasupersekret_from_file chef-11.8.2/spec/data/bootstrap/test-hints.erb0000644000004100000410000000046112254362222021215 0ustar www-datawww-data<%# Generate Ohai Hints -%> <% unless @chef_config[:knife][:hints].nil? || @chef_config[:knife][:hints].empty? -%> mkdir -p /etc/chef/ohai/hints <% end -%> <% @chef_config[:knife][:hints].each do |name, hash| -%> ( cat <<'EOP' <%= hash.to_json %> EOP ) > /etc/chef/ohai/hints/<%= name %>.json <% end -%> chef-11.8.2/spec/data/bootstrap/test.erb0000644000004100000410000000003112254362222020063 0ustar www-datawww-data<%= first_boot.to_json %>chef-11.8.2/spec/data/remote_directory_data/0000755000004100000410000000000012254362222020753 5ustar www-datawww-datachef-11.8.2/spec/data/remote_directory_data/remote_subdirectory/0000755000004100000410000000000012254362222025044 5ustar www-datawww-datachef-11.8.2/spec/data/remote_directory_data/remote_subdirectory/remote_subdir_file.txt0000644000004100000410000000007512254362222031451 0ustar www-datawww-dataI'm a file in a subdirectory inside a remote_directory sourcechef-11.8.2/spec/data/remote_directory_data/remote_dir_file.txt0000644000004100000410000000007112254362222024642 0ustar www-datawww-dataI'm a file inside a the root remote_directory source dir.chef-11.8.2/spec/data/null_config.rb0000644000004100000410000000005612254362222017230 0ustar www-datawww-data$__KNIFE_INTEGRATION_FAILSAFE_CHECK << " ole" chef-11.8.2/spec/data/environment-config.rb0000644000004100000410000000006712254362222020542 0ustar www-datawww-data# # Sample Chef Config File # environment "production"chef-11.8.2/spec/data/remote_file/0000755000004100000410000000000012254362222016675 5ustar www-datawww-datachef-11.8.2/spec/data/remote_file/nyan_cat.png.gz0000644000004100000410000003514012254362222021621 0ustar www-datawww-dataK"Qnyan_cat.png2uP<[p` . \%@kpw.rq.A7v뽪gkkwfz>_(%i4d"d(((4Y O0S h5i1i8ߡ~%S˨)BAyBAq ;ԙ &> SUw OKCD Io6Y[f !(FayYg  L hmg*<+/2YGK0Ozh|z+ձqñdžg=McעMRZ:*y|GZ0y1L !p8(HlO}L'h<"J(49e~BB,6Rhk@F18e >ӆL>bp=[m(+ETR {c3G3>kRGւZy[Ց0~QVӟh T4d`ШAtzE3XBUt /c~:ڿ+g郫 4*Qi;"+<=S׈ IÐG c&[lDZրI- {oLvCRaiEr3{M>gڞQ!?,eaDAb\EMH|Gt0w™["Ez :([#zC+hnXD/=l;[bY Oۆ;2ƍ\}+C1WCA@zB(R ࡷ;7n?0'Ǖh'S2b̒U b3Y44 V8O2:%<5` ={ s` {|LR07lhY[B+"| >T{7+ iT\2C 2t~zqzLRhi22%cUl^N'wI QK'UFo~3}?CEiGґqB]-#: I]x)eAj)x$vYjн kvDctaKErD1YI>}g@$ƶHGߨU^ǼA3daTKo|9oj>:$jݮB< 2?34(64`\@CjI!$/6 +$=ZI!G~_U[LT2W5^8 NB" l, K<'vz6?m'VÉ#xD|d T@ )wWm'LE хԖF0tQ9JU9,sk9Oa璫pMp,z#f?0K%}Th  ;~So -όz!cwR%>]&e|:ObLXO6aI&R;y檑G(ЦcKsu X`U2aKq0ƤQEB@GMQFAcJT[c'T'ێ et_bM,Suk = f/Pwљ6>'KLPy$:Owe*i7X;-27G|Hs=~ }E4x~ofI'xO^}iE}'0r#H,xyp)jy锹 Tf۰yY';KU&iK&C0[E7RZ8onR,kDH4WWA @9xϚ"'XIU?T+-ߚ6P Њ;Ei-bɁ:]oQV->䬱>)fɴ>);j0yųQ_5(7RhK9/bϕ3wO0J,t M.MYn Mb+Yi-S>Fyb1P6uc! 9 H*70Tvv8e/Ս,L1`wa=bnʉ}OvO1sٸJ5^(NպbNK;Jю"g`OcãS_D~3SonlD cOzGcХ'DYlP1d<yAY1DfTfxRuH\#rn:u%t;*l;׬ךq~Ѽ"-=:48 03шȫ$g!T"TQw7*AfYm݌+&G.RWti(U,\  f@RHErD m%_9I5AbvoDNf4#0(8ua›YH$Z= ǔA``ҪSrSi`+ #{P;@;2}on)BǮt?_|vj} ;]D{1ݚ\K#ǽOL3v&e8(?;+pEA;N 6{>Tg t?{?-11T22ly Dpx Ns4 '~S3]! bVά?RhSSš49 Vs`\ˏkwyϸ n |8#{ɔ+%ynݶfS]|SsLFU KI[9ELa7PLϼA(Ɣ#t25m)놼Zyoq0iRu%ƎR%5ƃ lAo ``Q9>E㲾Vc (;K2'.1QhƀmR/V5xݪ~?}=EI ƞt@hEnsݱVwcQcQ_M9U$Ƚ}S~A>a"X` gB{)wȁ? ќ: `BiRvl5g\x=V6龝:pF׼k:{%Ńv+1ZiM%$D 7 (˪+"=&vHw8v\udc'6P3?9C e/-{z~W+[ĒScO'8aܿ| B͡Z&/pAr bO1Ssl}r9U,jPۦAΉƵ=8\Uuy?Zh+W?ŻsH 2+)C?bmT 2nJ.w"w.Zl9If9. 0/3yU\(4wo|p6y65x{nn4CLΠC q {+۫LaS5U|$wBx >n d:F;u!jE6PEx5H;ƶd< ;L` A]{M~Ft|7v}'Tp @$3V5mZ++1r 7͙5 RلPͣ7IݗE(\ZMhXq'!HCd1 V^!el_@ؑ=`)YgKXy+\eS֩eas̱BMXۥPT@32C;2YA#Z:4XJg.Sp.Xv!8,9nKLP+0 bFy g_S>&x3>x-||t+׼mu\fr./IUG# }fҶvgRi%ӅVnfLsikG\&`!jTTJz8WDKeoc!{Fblqdn|48uqlK|?8>80){],5JFj|\5JǙ7rdwn$=SHoD֠ ː_D|M Ys9rhS唩.h9L+OWfڜ BT Oc *T[*je3##ux!@kߜyA;w j;84tHU+۬QHg^3. r38 mʋI Ș{=C<*0\)Hx-ɼ;VEO 9a-U(sA/K #}R SeAӬ$_DZ t^W8,! "+`oRbpv8N z7tZɨՆߒžLI;b((F,~P~0C Z@ cI? ZR0ϖw<{D W4r/,'6?^ g[pp(&8QS#w$|Sc7y,t[t <:[fCB48: uR5Fh!@W ۃ :ɊG&ߝi:iMX%:xFin""av[]\OBGᄥQΔS̯~~s~cCl44aa#VW54C6Z5:x^4cYiE2M_a_{?c!lˣP[ {: kcd 93THIݡHzU@4 X,Ai̮ZXABG)?Wh,"<a4OY>rwf'0%X2C?덝AٚpHl?hoƃ7?qP <φbJWד{S)L6+yyb,H!q ?|rЊFbY8~:S.ePKmƘȃ~bTǽPVT-))/6(sxS~UU.弝_Ҷ:8ʕtÈH08P6 '=0f5-{!vUzS&h|zV`yQ͊q'u#*ǔmCG]7k 95k}9=io5|<+' Uύt @I`qo@[~͏rElZk*w8im-#e^rqM>_;R O. ;'2k$lNqR jMe9zդ׆D豿-,-nj͚`́0D؝pb ڳX>b/p?ojvk-_t5x?#3` 3tЂPM 3}&]4Jt†]+z { OO .<jńl=i^~Y%;FD]*Umƿj t,ab=jOq¾ݗc &|~1|!Ft .Ty*Azw (uRf&eXC*Ty?Ta涘(jO^X9qWƶ(~-tB[wOIᩮ"d)&Zm,:a zn* ٕ4q2_'&u yaTthW>.-sG+lR&*`O28%an(_̀A'? Dظ? #kqp% vY _s}aNG_ўU# QFbJB(70/ 7>BUCPu]r}] y_,")4ؒܮZH=H%f F?)Hn-+@FYI$ 2^T{!n4S}_ENx br8hznOu9oV&饝q?hD?AAyÊ ʿl {_P. pSLġR!vPg]؁,,hvCp[U w&՝|N%٫\k.q(onei݀q=l6OQ4ļ8=)rܷ̿ZQwa.=Fh"T/mH ~QotvAQp]>Dhߤpz]vn J8bnai'A-*~jmb,'Nѐe%D6Ӄ\Z6V9_Í!gϳo  tg|Vќ&B/8xA˲aB崃!sOG9V3xusҒ ŅmK Sha3 A(܎ zS;aԤ2=iѺwb^ :QNtB}B[maXR@-jĆJ띓 zMiז{J5t ^ W+$s+7+7@+Jyn ({=b}@bNJyM`6)Wx]LCIC*܀B ao|`6 MmmPܹ,ןOK_{}6LZb|sV^ B@|aAޝZkI<'u\\9W"}2?=#MҶ v{[ôsWòog3A$PE 5+fyj\;`Ԃzi]$MSho+@DF&74Z'HEŕ%Rps3YBIH !>rWz ?c=[08TOvonED#Zl0}{15 M WEh([]Nw|q┺#nr5k.${pC 7v:n>,O3u1YۿMb X# KtNSs_ۗST/G?>TОKk*zskws~sNB\/%Y>W5OX #huuC$MnO]pI!i^3F>xEyq߸M.SOH$/7^p)gxk'G3NrzT%] ˕XPq0Vw+}挪4FCĂp?ڤٍ 麷At0a,/3>ٷy0y[P`xt O"H#pP8@Ϝ(&Y|aU\9vaClxFbE$Gܹdhƾŭ]fR|4 RT|oB aRs{m9j{ť;u;gX~s[up(YZ\na譴nĦS ohã~'Fy?﷯[Hs6? Syj ɚ9wr*~ R 9`T0:>mЛ ]o~gJXA:r@39ӹ̔7ًDkGoB|n3xXpΘ_b0p[{T\lnZ9;M 81=x!t0's?QȆݳ\Y{`ș's }_n+Mwfez^!&Cxah0 هVPvμG3Y) i8Ce(.i[Sw s+JrFD_[ar d*lj/݅k'f ءt\N<9:jB #i*_-ʻY3<]f_py,8$n𻔤xz_?P#dksl`|T"lIb(a{^=6d d*_?}%) cw6h奙FII!}^nn@cd I,hX݀0o{ڡge _^sIkĻiX?w0bApFAEHF] +(}t.Wvؤjb gʗ`2aՌuVШԋNqE5;11zŵC?Zofō?M&?.K¼LK)9r0Qp:ve}μ,F8yl UR ߍ'z ΫT1[^NTm[I3yDߔf.OzTA!]k=O>7k%KxsAWS.$d7ʒO4o>+ޣi;<^,p΂+:nbd:}ݘ!jJF]<\eayq~TB::|ȝx'߆!O64;⯑Γ;Nع 㭷Uy:mc\f? ؇ٳ|LWCD&o3R3c9Y}9ma"Խ7 E,x%k[$J?K UEwGs]D&_(,bhH 5@YjKE[{MlZU9'Qe귰ϣC]/$DsKx gKs}+WVWL׉t2%GLxRg;DJ{V{379=Eʾ ]&~jxWv.jtUu[4nMd}"C-#gɥQ^aO{\-g6P4eó]u@im| uyy<7Üx BЮ!KtϋHR5+ֱPMzsh ;jKNxELL܌+彨t(~^MNZRgτ&(>OPH͢1,/oPh_9 8+5zu" w[4/t%[7=CP'zZ*HJ]bۂؤK%K>Sæã?}tHY ^G Mr*۴ cd#oM&A;ٿ-%uC9:<}wm)>^h@hmqN&Z<9'IY倹=_# Իp-@+|*ɤIn~yƚkGSosYu1nhHiEIPK"4'a \xKUJ_X}c-%:wj%m˝bwce{eƚpp- z- QvȢ VY$U|7!jQ[#wR߸[ OOJgɿx(Ws2_^0,ث,[am9<|xB!H%Ը*+=eXbkjfC4XV%LgRE2&[˷x@9PRr}0L)ZCȦL 4-ɀEBm~AygY~)kxcKbj|7i3{ټKjȼey_ '655,|{3vG=RĞ}͠{8rO=4TCa18LOO%ƪIZpmCFJr2;el=b1OüFߧ[5?9uѝ6%Hٹ楝0 ~fJGޘ=7}}M8٩Y7<1k&d-Z)Eo/u0M{ bg HKerv]JőfW3`t,tߘ[yʷu#{Qy"DhB3*>?1wIO\RpZH5%1/5cxQ&pʨ_PE]Jb&A\F?b;chef-11.8.2/spec/data/remote_file/nyan_cat.png0000644000004100000410000003554212254362222021210 0ustar www-datawww-dataPNG  IHDRjsRGBgAMA a cHRMz&u0`:pQ<:IDATx^]`:"Ez/I,XЧ 5*`(IriPDT|O_TĆ)"HIof6{{{$ޔooi6⸕TeEGGJ)ق/Icc ϡ(ji >L)%R:IH⦄ #=˳Bƪ2_GU 겻Xy_y/ϞŤ:^:uR. lAɤ@_bTd(1T5{Fh<VxewQ}5gO&L#%BH \WΉS;'ɏ#G·$~{4.>Tio Qw]Z~#{. T](6X z^нlBGI\(9qRݾx~_&mid կYnϞaILOHyeb) %P]o { o_]r,$ 55H E$ܥ,$jjzTV»![;5jУc#i5!%uSޗMTCFMrرqӄ m b̠H^cOҎ7EASaϦv&HJv'.8vE<ݽ&ygBzXaw>j`7ؒ[k@~݃zC ёppoC۟ΟEw~7:|?u͒p7QR_DOD8"5Ќ%0i 3W~./Tq1.DCo_ۖCa@>"BvϪ ~_xsO撄Pn3Ur/P45?wC (%}pns(ǖK F+.bY HK XHjeUl& w) IBMJNJ@]JBPSnp,Tۤ$ܥ,$ 5U6) w) IBMMJ@]JBPSnp,Tۤ$ܥ,$ 5U6) w) IBM$͛pn *įSXh5M,@%BP$ty>\ L5$LcWPk5~HH7.g-(6ĕ> 1&<pI ]o'O?y uZG~`4hapΤN;W2@J \%)%$ %`* ' kG+I"vԀ+c%seeZR,a"vp_„vWܳ?Ͼiӯ?cF6 aBwrνd&+62pK=~\kyHz8,4Ǐ{k~w;^=2bp9Gx}ݡ}|&Vaf3;^u쐟;0@^iq,ݥjK6AT1R(g0)*z _7YJ i HK XHjV*^Etj鏯HLX ("pLh#6 F+Q;$ty⤦z\ &Cn'Ud$ܥBX7g{.{QIb&E{Iȫ7gC *R,Q=Sa4=uQ>jѳW9GGſpbciT87NJcT=P=1:9̶DjSUz^qBJm6JFx|TԲ=Nq O!=?U(Nx OQDpR:^v%g G=Lto+41`7o@J+ \`QBfl|p׼)xp XnGI㿄`k1Jz4muf=lt'm{~{Ktdy+`m9~ ICH1!rvL4" {~zhz`S,XB8RaX-SUŘL}RNc;ÂSeo*ٞx[vU;Z=5ˢ+a1+32fc'[Up7[A~漓ac/ T p&HBB'dA:]??a({ v83ȡ;K۔-SC?r_x1;m+8W3u WKQw6*c;|.f޼5Pa-z3oeW&FI~8*T2VB &ofMw,שL-9!QrQ%:iN啅EKݿ:K]KRp,dυ?uUG,Jlvb!l,ȫh)}Gj[0Jt]A-oBKi&]FEҸXZ}-p)cl K[K;O׼|PLrH?; 6NS ^YkDi Uъظ |> 6OF o{O)kpw@;k^ޤOQ<5Tf+I9ʅ%Ǖ|UCQ^Nޣ$f+}TxjQYլJX@Y4f lZ5&eU`f3T)gjT61nˣ~ e>un>%}ƯTfӸtl ϫj5r?&zjNke*Q!Bw :M"Q^N^#WTh렣"WJ?=!4*Lo>Ly0ģn?I3^2'eʊS)§&A l2hY t/^Hݎ*pB ^-}E}ýSLYVI e_EsȏUVF~x?]U=Sl#f lOдwv@ `Mh߉QƵn:D9=|7eYl'XJa6KQQXa1bSO=% XzB*2DM j0Tj' ̧o+|'GUNp7-(N˞nECT%)mB 3!z:vpߘQ}[5GYCM〺7Grk+k̰a`deejY@4 +m:hI 9t_z;a˻f`cȴ;fu[LWv3z8B}=_-;-:?!̓rѮbxrŅO)Rl**6PaWՠ}5pOMME͛ʟ_zURUE%M0pTI6f4ca]*7l0Gp{Z3fKZrGa6F894vU}pQ{`]o^{+jNvS%oSVB,$wn wp3?!7_$}՛&&&nZ3OgY9q3} ]wUe; ÿkZ+VjQ_=S^koůW]uY0\h-ሄRh1HJZRҕzRB,( T*0d';ULp耭_~ڵp[N dӦM&L.hn\Kl`W6$D -竨;[9 ի m4DEq!h w3Cost$UOJ(Qѓ%0It-:juUy6…<&y3| &9#GCX~*,ì`,=,8U' LR'ڶ06klm4Pkh!=ԏZGz{ΝI4kJ?&̰#hW*R)'-BR 饐8=Y2@!𤋮z`ʘ>/!}qnC?=#`F{,IbRsA ļyĄ} HC\D})ٍfܬQ 0y4|c>3Pw|JǾL7{p3g=uԑ׏->n8|"Mus0%R{]wݍ7xcZ'}lHH &XƨܓVjdIgŸ$ ueaT=ְI ≸+‡ٽlwL0Zfl(UbEyW^(w !.O!rM#Mh5hnS/J3$̠tuL&lPU!^H*&u/i%7n0.gLp1rމ^ZUye=+}mTfz&q?m޼m~曳gxGEܟc0 E=s(筷Bxl1]Ldx0~LG׉,w:Nw5B+T&tIt œo^$;&c?'P ذe)4O1 VޖG~T=]mWFzF݁BX\MIIЇEQw^K/T4ZQ[pX7ԛP"1KU;9{&4jXxʖTl~YhFQ1Q^>|8 Vip7øW%%&=^4ȝ2'l{N`;L={qg\2". ٶm9qB碨ѣGy펾~ǰdT/1$jjH9kwaO{-1k`':Q ~w']ɣ-pݿ[M%_tEa&MQ^`%V 駟jEᢨQFIcbIy=\^ise_ֿMx6hWРoՠ v ԯ_c_IQőKo7ߝ3v1m&_9lw1_ 0a@ 7o\p,YKh.8]s=\h( p3fʢkv籨]ͱP,GǢWG" *KPZю1}чq=|4v1ţfÒ{KwxHŲUiii]?`͑/M5xQUw[--K5cf1Ne&f*;;hg'='NU} 07"=z/$x}[}M7%MHvUn_nnĩp|#n6,"ZVTZ΃|ٮ+ Z4n l_H's?~mK` #Gawe3cR0{,-5hwgrr~='HnOx47'|;̛'v!\I}.H\/hzæJ`̛ܹY WhaϊH;`Ľ )Ӛ7J(Q; BᦕyǘO- aU0|ĥ sa&Æcr!#Iu3|j>}|$Vɴ #uY:" ;>nb0FX,btVx1A鵔b$Q;TXg~>uzUF&ܙ}?'vcr0CРAFE^Cz~ Ęo X ̶K"0fl/b`͔[ⴙ'1sj3#99rsiNNYnny8 #bÌą^ɡ8Wlӹ";RʫC%N'-,<p3^^*CE! fgg-'`Fl0eح{Vh`gp|,ѭ!)½+b, ׬Y|)O 0v~.1"=,~{-tV:Zث-u:H0FmyPecJ=WՂ s w&uGa7`X&wIq>^r.,i^x6f˜y<@"w1roY. w-~_>Lv1FLA^h/\NҔeřlߖ) ۼ%LXYsMD(0]ڷ~$3b.̡ۣxl I$J=T;qB؍;zSVғ[zRC,K:nJԦO(gzuffa<}@_H䵘`">)^ͧr4ܦ _Ϻc ?y[W*wegUvg)oQMAo5GQӇ4EU9/%tiӫy>8,oN bZ x͜9S|'P#4=C;$6%۲"ﰚ)}X:ޚ%h4 ɼW^ >ů>|F[e.gϙQ VnφU3N'ݕ #d~1DsC$0D=Y=r`mP=p7D_hbmTܘF+L#w08y1$O{]NO:PUR_{;sӒN(q記zb!M=lPV%z/x[Vl2*7ٍ!jИeY':;o9M&.hq,ot)VFS0-ԎpHk1‘{ADM1TUWT|CE%֧$wW;7[N,zh-S,<߈( Gy>%|Vaw//Wи<x<( X'wߖ#s#h0O)TZ&RpOO*H7}6} ;;n?԰ZbcL711q=8a Mh0iD (5o#Wկ¸SNX$;VM0 `ZAYO[Y%C1֪֫ӓJ,4qM,-"ĵaX`>ᝦd,:iCII2< ٽpI:l\1c{=#tPlmpq\ _{S1O 4=~\;3cϨnX_ *}EGhA߀5G=]lvSkyX; Kl(hN'[ ilkwx4: PK5!vfGIuh;$a*@]zsI9NKҴ^lؒ4lÖ7應`FXP[9r;VwsUt\U;p(cG{9pꑲy1p,څ1uvРn&)cI;Qt``![vctw|V,_5^?죁-3`J@OkA".|0fD2VJ7:uIHɲeo\f)] \-E^A`jޯPg9KqQD'f:d&;xǟu3t>2)lPgddh]UOC#=I<`i"tyw@"V BVwfpoWn=  +FwOius8/pc WL=S֮֬]sϚ}s&V$eUӮj㟦x ;d 9*sPfc3;_{RRLl~b; ZHZ%٠[܁vl-:\ql%#ąMܳ+&pv*m QVj_^NJHvIjwyζrTÊՅ3YqD004Gq.ZQ F`2y??]dlKNk59<7.&z`0@Uq#4bye`Mړ': eO8L:$arLjغ0Z3j~%16K.6 ҘBz]_AvJVx]xN: C lsVMu FNF}S^y @{PgzU$:/B@ඊS*6k[ ;<OcrU8**rU!ӿy,w> PKT9V+[ 84V!:%ܥ,$ 5::Lԟ$ܥ,$ 5U<) w) IBMMJ@]JBPSnp,Tۤ$ܥ,$ 5U6) w) IBMMJ@]JBPSnp,Tۤ$ܥ,$ 55Bu[t~S@ $ J]F71:۝L #4 JTomw-n~`$S Hll?Co⻟? I]=@ ~օR{~Y{/[$!RmW~mk wULCVpph3[1s!R@$5UCU=,RGvgtxc\˧`#M9!rHRxVl '5"HKݖ|+>۟QLIi%q6S>|$W40H܈v=+nN2ɅjI*6JAkO qdw?$`7< h0^n/ON?!:gP +6#3Md*" f>pQsI8?,~ڻ;{po\@ n#prÛ&pp/}/c, -(P]½6J@3s^>ˑ~G@>;3I<{3s<my#1s-YWmLmKG®L5%`j4AD{!3 S-nuTd.p#џ/hn.aX9$pOJЌ%Wߙ `LI>V3ᙁ\ ?d3ߝM.))Lr\T;~oʈ2y"=a'x2p!2{ɥ%$T쪆 !i-Pi[Ml*XIbAw@gY$i'@-y77HfȞ 5B0l\_BKRR*1) w) IBMMJ@]JBPSnp,Tۤ$ܥ,$ 5U6) w) IBMMJ@]JBPSn"١(bQ2@*1"H;>E)Z+*=ݞagqP ”LjD 88tO:}ĩlyвs=k-:;C)---S>p0e@jbpc6'J^9y\5$U{b/ڹ?{<|!Tݹ z#xj%V@*NYB+(^ER$p5J@]JBPSk,հ$ܥ,$ 5J@]JBPSk,լO " ?:IENDB`chef-11.8.2/spec/data/search_queries_to_transform.txt0000644000004100000410000000543712254362222022754 0ustar www-datawww-dataafield:[* TO *] content:afield__=__* afield:[a TO *] content:[afield__=__a TO afield__=__\ufff0] afield:[* TO b] content:[afield__=__ TO afield__=__b] *:* *:* role:mon content:role__=__mon role:mon AND role:prod content:role__=__mon AND content:role__=__prod run_list:role\[rubberband\] AND run_list:role\[whale\] content:run_list__=__role\[rubberband\] AND content:run_list__=__role\[whale\] sharable_server:[* TO *] content:sharable_server__=__* run_list:role\[nfs_server\] AND sharable_server:[* TO *] content:run_list__=__role\[nfs_server\] AND content:sharable_server__=__* run_list:role\[nfs_server\] AND sharable_server:[* TO *] content:run_list__=__role\[nfs_server\] AND content:sharable_server__=__* (role:prod AND x_y:true) (content:role__=__prod AND content:x_y__=__true) hostname:[* TO *] AND role:prod content:hostname__=__* AND content:role__=__prod role:t_mem AND role:prod NOT hostname:ip-1-2-3-4 content:role__=__t_mem AND content:role__=__prod NOT content:hostname__=__ip-1-2-3-4 ohai_time:[1234.567 TO *] content:[ohai_time__=__1234.567 TO ohai_time__=__\ufff0] ohai_time:{1234.567 TO *} content:{ohai_time__=__1234.567 TO ohai_time__=__\ufff0} ohai_time:[* TO baz] content:[ohai_time__=__ TO ohai_time__=__baz] ohai_time:{* TO baz} content:{ohai_time__=__ TO ohai_time__=__baz} tags:apples*.for.eating.com content:tags__=__apples*.for.eating.com role:safe AND ohai_time:[1234.567 TO *] AND whiz_bang:x5 content:role__=__safe AND content:[ohai_time__=__1234.567 TO ohai_time__=__\ufff0] AND content:whiz_bang__=__x5 role:safe AND ohai_time:[* TO 1234.567] AND whiz_bang:x5 content:role__=__safe AND content:[ohai_time__=__ TO ohai_time__=__1234.567] AND content:whiz_bang__=__x5 animal:[ape TO zebra] content:[animal__=__ape TO animal__=__zebra] animal:{ape TO zebra} content:{animal__=__ape TO animal__=__zebra} ((value:[1 TO 3] OR nested_b1_a2_a3:B1_A2_A3-c) OR value:[5 TO *]) ((content:[value__=__1 TO value__=__3] OR content:nested_b1_a2_a3__=__B1_A2_A3-c) OR content:[value__=__5 TO value__=__\ufff0]) ((value:{1 TO 3} OR value:{1 TO 3}) OR run_list:recipe\[alpha\]) ((content:{value__=__1 TO value__=__3} OR content:{value__=__1 TO value__=__3}) OR content:run_list__=__recipe\[alpha\]) words:"one two three" content:"words__=__one two three" words:"one \"two\" three" content:"words__=__one \"two\" three" words:"\"one two\" three" content:"words__=__\"one two\" three" words:"one two \"three\"" content:"words__=__one two \"three\"" words:"one two \"three\"" OR words:"\"one two\" three" AND words:"one \"two\" three" content:"words__=__one two \"three\"" OR content:"words__=__\"one two\" three" AND content:"words__=__one \"two\" three" words:\"* content:words__=__\"* -version:0.9.12 -content:version__=__0.9.12 !version:0.9.12 NOT content:version__=__0.9.12 ec2:* content:ec2__=__* chef-11.8.2/spec/data/apt/0000755000004100000410000000000012254362222015167 5ustar www-datawww-datachef-11.8.2/spec/data/apt/chef-integration-test-1.1/0000755000004100000410000000000012254362222021667 5ustar www-datawww-datachef-11.8.2/spec/data/apt/chef-integration-test-1.1/debian/0000755000004100000410000000000012254362222023111 5ustar www-datawww-datachef-11.8.2/spec/data/apt/chef-integration-test-1.1/debian/files0000644000004100000410000000006112254362222024133 0ustar www-datawww-datachef-integration-test_1.1-1_amd64.deb ruby extra chef-11.8.2/spec/data/apt/chef-integration-test-1.1/debian/copyright0000644000004100000410000000167612254362222025056 0ustar www-datawww-dataThis work was packaged by: Joshua Timberman > on Thu, 30 Sep 2010 09:53:45 -0600 Upstream Author(s): Opscode, Inc. Copyright: Copyright (C) 2010 Opscode, Inc License: 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. The Debian packaging is: Copyright (C) 2010 Opscode, Inc () and is licensed under the Apache 2.0 license. See "/usr/share/common-licenses/Apache-2.0" chef-11.8.2/spec/data/apt/chef-integration-test-1.1/debian/control0000644000004100000410000000067312254362222024522 0ustar www-datawww-dataSource: chef-integration-test Section: ruby Priority: extra Maintainer: Joshua Timberman > Build-Depends: debhelper (>= 7.0.50~) Standards-Version: 3.8.4 Homepage: http://tickets.opscode.com Package: chef-integration-test Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Chef integration tests for APT in Cucumber This package is used for cucumber integration testing in Chef. chef-11.8.2/spec/data/apt/chef-integration-test-1.1/debian/source/0000755000004100000410000000000012254362222024411 5ustar www-datawww-datachef-11.8.2/spec/data/apt/chef-integration-test-1.1/debian/source/format0000644000004100000410000000001412254362222025617 0ustar www-datawww-data3.0 (quilt) chef-11.8.2/spec/data/apt/chef-integration-test-1.1/debian/changelog0000644000004100000410000000051312254362222024762 0ustar www-datawww-datachef-integration-test (1.1-1) unstable; urgency=low * New upstream release (1.1) -- Joshua Timberman Thu, 30 Sep 2010 10:09:34 -0600 chef-integration-test (1.0-1) unstable; urgency=low * Initial release (Closes: #CHEF-1718) -- Joshua Timberman Thu, 30 Sep 2010 09:53:45 -0600 chef-11.8.2/spec/data/apt/chef-integration-test-1.1/debian/compat0000644000004100000410000000000212254362222024307 0ustar www-datawww-data7 chef-11.8.2/spec/data/apt/chef-integration-test-1.1/debian/rules0000755000004100000410000000067212254362222024176 0ustar www-datawww-data#!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # This file was originally written by Joey Hess and Craig Small. # As a special exception, when this file is copied by dh-make into a # dh-make output file, you may use that output file without restriction. # This special exception was added by Craig Small in version 0.37 of dh-make. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 %: dh $@ chef-11.8.2/spec/data/apt/chef-integration-test_1.1-1_amd64.deb0000644000004100000410000000327212254362222023562 0ustar www-datawww-data! debian-binary 1285863038 0 0 100644 4 ` 2.0 control.tar.gz 1285863038 0 0 100644 464 ` n0P 6%Rݘ,F$mr٭*͓c'ɥA%z6F)eZ hRVNe|IU鮅Ko\\x/KOXcuH6?wpo5#T ID |dE66ק( I"F  Al>3U6zPqd5(c2OhOپ=Z^3`ԀBtd{׉=SU^^CPz2NL16o,=  +)xLT;dT #D{)|*1GCh9(aD[}IovNvGAW@-V~_:l6UGN-+/#="}s1c}! b "D.j kF6‰g:o c! |݈́Nd@D r b9{*VF'*LNJH&&ah4\'Jb4JaXN%6³~ %QbuneQMR'γCQ`8DR$,؏K95Qg1kiwB䈰Wubk (=:6w*] "J6Vn^P{B/D"H$D"H$D>V( chef-11.8.2/spec/data/apt/chef-integration-test_1.1-1_amd64.changes0000644000004100000410000000144612254362222024441 0ustar www-datawww-dataFormat: 1.8 Date: Thu, 30 Sep 2010 10:09:34 -0600 Source: chef-integration-test Binary: chef-integration-test Architecture: amd64 Version: 1.1-1 Distribution: unstable Urgency: low Maintainer: Joshua Timberman > Changed-By: Joshua Timberman Description: chef-integration-test - Chef integration tests for APT in Cucumber Changes: chef-integration-test (1.1-1) unstable; urgency=low . * New upstream release (1.1) Checksums-Sha1: 43c5653a9a5b9419849173a4ec3a9855cf0327a3 1722 chef-integration-test_1.1-1_amd64.deb Checksums-Sha256: 84e2f087f7e11d1b73743007ecfc6b8b34e03f6917c0993b35c0758ee59702c1 1722 chef-integration-test_1.1-1_amd64.deb Files: 4b05bace483dbca54efc21f97ee47e1d 1722 ruby extra chef-integration-test_1.1-1_amd64.deb chef-11.8.2/spec/data/apt/var/0000755000004100000410000000000012254362222015757 5ustar www-datawww-datachef-11.8.2/spec/data/apt/var/www/0000755000004100000410000000000012254362222016603 5ustar www-datawww-datachef-11.8.2/spec/data/apt/var/www/apt/0000755000004100000410000000000012254362222017367 5ustar www-datawww-datachef-11.8.2/spec/data/apt/var/www/apt/pool/0000755000004100000410000000000012254362222020340 5ustar www-datawww-datachef-11.8.2/spec/data/apt/var/www/apt/pool/main/0000755000004100000410000000000012254362222021264 5ustar www-datawww-datachef-11.8.2/spec/data/apt/var/www/apt/pool/main/c/0000755000004100000410000000000012254362222021506 5ustar www-datawww-datachef-11.8.2/spec/data/apt/var/www/apt/pool/main/c/chef-integration-test/0000755000004100000410000000000012254362222025711 5ustar www-datawww-data././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootchef-11.8.2/spec/data/apt/var/www/apt/pool/main/c/chef-integration-test/chef-integration-test_1.1-1_amd64.debchef-11.8.2/spec/data/apt/var/www/apt/pool/main/c/chef-integration-test/chef-integration-test_1.1-1_0000644000004100000410000000327212254362222032717 0ustar www-datawww-data! debian-binary 1285863038 0 0 100644 4 ` 2.0 control.tar.gz 1285863038 0 0 100644 464 ` n0P 6%Rݘ,F$mr٭*͓c'ɥA%z6F)eZ hRVNe|IU鮅Ko\\x/KOXcuH6?wpo5#T ID |dE66ק( I"F  Al>3U6zPqd5(c2OhOپ=Z^3`ԀBtd{׉=SU^^CPz2NL16o,=  +)xLT;dT #D{)|*1GCh9(aD[}IovNvGAW@-V~_:l6UGN-+/#="}s1c}! b "D.j kF6‰g:o c! |݈́Nd@D r b9{*VF'*LNJH&&ah4\'Jb4JaXN%6³~ %QbuneQMR'γCQ`8DR$,؏K95Qg1kiwB䈰Wubk (=:6w*] "J6Vn^P{B/D"H$D"H$D>V( ././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootchef-11.8.2/spec/data/apt/var/www/apt/pool/main/c/chef-integration-test/chef-integration-test_1.0-1_amd64.debchef-11.8.2/spec/data/apt/var/www/apt/pool/main/c/chef-integration-test/chef-integration-test_1.0-1_0000644000004100000410000000322012254362222032707 0ustar www-datawww-data! debian-binary 1285863052 0 0 100644 4 ` 2.0 control.tar.gz 1285863052 0 0 100644 468 ` n0`~68$hVۤI0]d~zT'!mi\\UB,fge쯪LH`A:Jgm۸O٠8/c/e@ )VovC]{ Veveq+K1rL':Xմ%@#drShRv::$"=a .8rkI(;oˏ|CMYu7T]".gg \M?YϒЀH߽WVCpsC>1 Ճy N2nndu&k ߂`Z6އ0YzӳrfzsHHO |&x:=T?dn IWB!B!B!Bھ7(data.tar.gz 1285863052 0 0 100644 1020 ` _Ec * R?G^L Y܉k.9 N6mv;^O}Q8ŗ""B/'"ȩ (g7rV'e2;7Z -+φQ \6 S<X3"\D);OQE-,CֶFհֿKmko);c7B`cƵQ_WjUuw<ا:;{__T6ߴ_HMӬ.:q{6n'(;o}Br?u%3`_\]gc0vyb|Oܻ4\y⅟ μ=_oa_[9ҫ3*YzsG]zr#/|'ݏ]ْvFnNr q:^]b ;SU !A B#w0( x2/F&(>9=y̡]:?9 4C `?u?2a'*U]Wِ>bѨ]W%GUj PCQ ͇.AG= 5+%x GLT; ?\|,h!fX8#>|!H<e ݨCC'ÑGzK@|y8iI(V+Ӎx`?1DB:"J%@#@niID8 0㉸2?]"D!o8D đ Z`ֲ[Ds j33F۞nAsƔݶ 1{jCnLca %QZoGA;G]ƢpGq IX**!v3?>]kDlg #YAa]o胢(bM0-:-4[Y{xMR|I$D"H$D"H$WԨ(chef-11.8.2/spec/data/apt/var/www/apt/conf/0000755000004100000410000000000012254362222020314 5ustar www-datawww-datachef-11.8.2/spec/data/apt/var/www/apt/conf/incoming0000644000004100000410000000011712254362222022041 0ustar www-datawww-dataName: default IncomingDir: /tmp/incoming TempDir: /tmp Allow: sid unstable>sid chef-11.8.2/spec/data/apt/var/www/apt/conf/distributions0000644000004100000410000000020212254362222023133 0ustar www-datawww-dataOrigin: localhost Label: apt repository Codename: sid Architectures: amd64 Components: main Description: Apt repository Pull: sid chef-11.8.2/spec/data/apt/var/www/apt/conf/pulls0000644000004100000410000000004512254362222021375 0ustar www-datawww-dataName: sid From: sid Components: main chef-11.8.2/spec/data/apt/var/www/apt/db/0000755000004100000410000000000012254362222017754 5ustar www-datawww-datachef-11.8.2/spec/data/apt/var/www/apt/db/packages.db0000644000004100000410000004000012254362222022033 0ustar www-datawww-datab1   SP  SP sid|main|amd64b1   SP   TPackage: chef-integration-test Version: 1.1-1 Architecture: amd64 Maintainer: Joshua Timberman > Installed-Size: 32 Homepage: http://tickets.opscode.com Priority: extra Section: ruby Filename: pool/main/c/chef-integration-test/chef-integration-test_1.1-1_amd64.deb Size: 1722 SHA256: 84e2f087f7e11d1b73743007ecfc6b8b34e03f6917c0993b35c0758ee59702c1 SHA1: 43c5653a9a5b9419849173a4ec3a9855cf0327a3 MD5sum: 4b05bace483dbca54efc21f97ee47e1d Description: Chef integration tests for APT in Cucumber This package is used for cucumber integration testing in Chef. chef-integration-testchef-11.8.2/spec/data/apt/var/www/apt/db/release.caches.db0000644000004100000410000005000012254362222023123 0ustar www-datawww-datab1   p7_P  p7_P sida p7_Pэh^pqrstuvwxyz{|}~ N3:1:91ca9531e3afa7a540cabdc6030c6f75d315fec7 :2:098c599ac5b0a98785336afb2bc9c47002570ffa07dd62321c6f70b9fdb74325 46cd71c965ce0813c94ef78c836cc7d3 104main/binary-amd64/Release:1:cde25071c5fcee59cee8dcd773ca419dcb40d946 :2:af601ce143f33405425746462973adc0fda3aceb381d1c739851b95ee0814ca3 92ed2cc14e37e9ab23466b27857d29ac 596main/binary-amd64/PackagesK K:1:ce04daff75d4b27371d691d645282b198045544a :2:15e98119705a08018d4583caabc91d36ba12e6f1c8af0f799a3ec8ca5bfaa80d c7726773341137b71cc971d44ddec4f5 394main/binary-amd64/Packages.gzchef-11.8.2/spec/data/apt/var/www/apt/db/references.db0000644000004100000410000004000012254362222022376 0ustar www-datawww-datab1   >`  >`  referencesb1  a>` sid|main|amd64Hpool/main/c/chef-integration-test/chef-integration-test_1.1-1_amd64.debchef-11.8.2/spec/data/apt/var/www/apt/db/contents.cache.db0000644000004100000410000004000012254362222023154 0ustar www-datawww-datab1   -W3  -W3 compressedfilelistsb1   -W3 chef-11.8.2/spec/data/apt/var/www/apt/db/checksums.db0000644000004100000410000004000012254362222022242 0ustar www-datawww-datab1   ^]  ^] poolb1   ^] :1:43c5653a9a5b9419849173a4ec3a9855cf0327a3 :2:84e2f087f7e11d1b73743007ecfc6b8b34e03f6917c0993b35c0758ee59702c1 4b05bace483dbca54efc21f97ee47e1d 1722Hpool/main/c/chef-integration-test/chef-integration-test_1.1-1_amd64.debchef-11.8.2/spec/data/apt/var/www/apt/db/version0000644000004100000410000000003712254362222021364 0ustar www-datawww-data4.2.0 3.3.0 bdb4.8.30 bdb4.8.0 chef-11.8.2/spec/data/apt/var/www/apt/dists/0000755000004100000410000000000012254362222020515 5ustar www-datawww-datachef-11.8.2/spec/data/apt/var/www/apt/dists/sid/0000755000004100000410000000000012254362222021274 5ustar www-datawww-datachef-11.8.2/spec/data/apt/var/www/apt/dists/sid/Release0000644000004100000410000000157112254362222022603 0ustar www-datawww-dataOrigin: localhost Label: apt repository Codename: sid Date: Thu, 30 Sep 2010 16:33:01 UTC Architectures: amd64 Components: main Description: Apt repository MD5Sum: 92ed2cc14e37e9ab23466b27857d29ac 596 main/binary-amd64/Packages c7726773341137b71cc971d44ddec4f5 394 main/binary-amd64/Packages.gz 46cd71c965ce0813c94ef78c836cc7d3 104 main/binary-amd64/Release SHA1: cde25071c5fcee59cee8dcd773ca419dcb40d946 596 main/binary-amd64/Packages ce04daff75d4b27371d691d645282b198045544a 394 main/binary-amd64/Packages.gz 91ca9531e3afa7a540cabdc6030c6f75d315fec7 104 main/binary-amd64/Release SHA256: af601ce143f33405425746462973adc0fda3aceb381d1c739851b95ee0814ca3 596 main/binary-amd64/Packages 15e98119705a08018d4583caabc91d36ba12e6f1c8af0f799a3ec8ca5bfaa80d 394 main/binary-amd64/Packages.gz 098c599ac5b0a98785336afb2bc9c47002570ffa07dd62321c6f70b9fdb74325 104 main/binary-amd64/Release chef-11.8.2/spec/data/apt/var/www/apt/dists/sid/main/0000755000004100000410000000000012254362222022220 5ustar www-datawww-datachef-11.8.2/spec/data/apt/var/www/apt/dists/sid/main/binary-amd64/0000755000004100000410000000000012254362222024415 5ustar www-datawww-datachef-11.8.2/spec/data/apt/var/www/apt/dists/sid/main/binary-amd64/Release0000644000004100000410000000015012254362222025714 0ustar www-datawww-dataComponent: main Origin: localhost Label: apt repository Architecture: amd64 Description: Apt repository chef-11.8.2/spec/data/apt/var/www/apt/dists/sid/main/binary-amd64/Packages.gz0000644000004100000410000000061212254362222026474 0ustar www-datawww-datamRj }+I4jLB);v00þĠd>=s 3vFvnNx&9?D~ayQ^'Ki bdV^:q5&a23ސ~{,Oe\.oy.1+S,>1!8\(Ic Oo~m߶Eq]UTFb5F9BKFk`m+PjUY*;*Z e[Ff0!cR00Qi#룊 )ke#z FICeғGrCG?ţx>O =.1h.׈ [IK BGTchef-11.8.2/spec/data/apt/var/www/apt/dists/sid/main/binary-amd64/Packages0000644000004100000410000000112412254362222026054 0ustar www-datawww-dataPackage: chef-integration-test Version: 1.1-1 Architecture: amd64 Maintainer: Joshua Timberman > Installed-Size: 32 Homepage: http://tickets.opscode.com Priority: extra Section: ruby Filename: pool/main/c/chef-integration-test/chef-integration-test_1.1-1_amd64.deb Size: 1722 SHA256: 84e2f087f7e11d1b73743007ecfc6b8b34e03f6917c0993b35c0758ee59702c1 SHA1: 43c5653a9a5b9419849173a4ec3a9855cf0327a3 MD5sum: 4b05bace483dbca54efc21f97ee47e1d Description: Chef integration tests for APT in Cucumber This package is used for cucumber integration testing in Chef. chef-11.8.2/spec/data/apt/var/www/apt/dists/sid/main/binary-i386/0000755000004100000410000000000012254362222024173 5ustar www-datawww-datachef-11.8.2/spec/data/apt/var/www/apt/dists/sid/main/binary-i386/Packages0000644000004100000410000000000012254362222025622 0ustar www-datawww-datachef-11.8.2/spec/data/apt/chef-integration-test_1.0-1_amd64.changes0000644000004100000410000000146012254362222024434 0ustar www-datawww-dataFormat: 1.8 Date: Thu, 30 Sep 2010 09:53:45 -0600 Source: chef-integration-test Binary: chef-integration-test Architecture: amd64 Version: 1.0-1 Distribution: unstable Urgency: low Maintainer: Joshua Timberman > Changed-By: Joshua Timberman Description: chef-integration-test - Chef integration tests for APT in Cucumber Changes: chef-integration-test (1.0-1) unstable; urgency=low . * Initial release (Closes: #CHEF-1718) Checksums-Sha1: b44685ff59626bc94c67e60665f06c4643fe9767 1680 chef-integration-test_1.0-1_amd64.deb Checksums-Sha256: da176f4405fa21fd7207d4785680c6996d395a1ca132f2d5565a61c5479b1116 1680 chef-integration-test_1.0-1_amd64.deb Files: 713722480408ecc8e7220aea52bdd76e 1680 ruby extra chef-integration-test_1.0-1_amd64.deb chef-11.8.2/spec/data/apt/chef-integration-test-1.0/0000755000004100000410000000000012254362222021666 5ustar www-datawww-datachef-11.8.2/spec/data/apt/chef-integration-test-1.0/debian/0000755000004100000410000000000012254362222023110 5ustar www-datawww-datachef-11.8.2/spec/data/apt/chef-integration-test-1.0/debian/files0000644000004100000410000000006112254362222024132 0ustar www-datawww-datachef-integration-test_1.0-1_amd64.deb ruby extra chef-11.8.2/spec/data/apt/chef-integration-test-1.0/debian/copyright0000644000004100000410000000167612254362222025055 0ustar www-datawww-dataThis work was packaged by: Joshua Timberman > on Thu, 30 Sep 2010 09:53:45 -0600 Upstream Author(s): Opscode, Inc. Copyright: Copyright (C) 2010 Opscode, Inc License: 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. The Debian packaging is: Copyright (C) 2010 Opscode, Inc () and is licensed under the Apache 2.0 license. See "/usr/share/common-licenses/Apache-2.0" chef-11.8.2/spec/data/apt/chef-integration-test-1.0/debian/control0000644000004100000410000000067312254362222024521 0ustar www-datawww-dataSource: chef-integration-test Section: ruby Priority: extra Maintainer: Joshua Timberman > Build-Depends: debhelper (>= 7.0.50~) Standards-Version: 3.8.4 Homepage: http://tickets.opscode.com Package: chef-integration-test Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Chef integration tests for APT in Cucumber This package is used for cucumber integration testing in Chef. chef-11.8.2/spec/data/apt/chef-integration-test-1.0/debian/source/0000755000004100000410000000000012254362222024410 5ustar www-datawww-datachef-11.8.2/spec/data/apt/chef-integration-test-1.0/debian/source/format0000644000004100000410000000001412254362222025616 0ustar www-datawww-data3.0 (quilt) chef-11.8.2/spec/data/apt/chef-integration-test-1.0/debian/changelog0000644000004100000410000000025212254362222024761 0ustar www-datawww-datachef-integration-test (1.0-1) unstable; urgency=low * Initial release (Closes: #CHEF-1718) -- Joshua Timberman Thu, 30 Sep 2010 09:53:45 -0600 chef-11.8.2/spec/data/apt/chef-integration-test-1.0/debian/compat0000644000004100000410000000000212254362222024306 0ustar www-datawww-data7 chef-11.8.2/spec/data/apt/chef-integration-test-1.0/debian/rules0000755000004100000410000000067212254362222024175 0ustar www-datawww-data#!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # This file was originally written by Joey Hess and Craig Small. # As a special exception, when this file is copied by dh-make into a # dh-make output file, you may use that output file without restriction. # This special exception was added by Craig Small in version 0.37 of dh-make. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 %: dh $@ chef-11.8.2/spec/data/apt/chef-integration-test_1.1.orig.tar.gz0000644000004100000410000000035512254362222024042 0ustar www-datawww-dataL a o`ivEajEpD1jE=0ƍDjFJ܎H*LPE¸`S}v\Yw4}]?S쀯D µ6Q{ugEy[>) bAE}?)kIǚqK|)7+lmoҤoڝv*(chef-11.8.2/spec/data/apt/chef-integration-test_1.0.orig.tar.gz0000644000004100000410000000035512254362222024041 0ustar www-datawww-dataL a o`ivEajEpD1jE=0ƍDjFJ܎H*LPE¸`S}v\Yw4}]?S쀯D µ6Q{ugEy[>) bAE}?)kIǚqK|)7+lmoҤoڝv*(chef-11.8.2/spec/data/apt/chef-integration-test_1.0-1_amd64.deb0000644000004100000410000000322012254362222023552 0ustar www-datawww-data! debian-binary 1285863052 0 0 100644 4 ` 2.0 control.tar.gz 1285863052 0 0 100644 468 ` n0`~68$hVۤI0]d~zT'!mi\\UB,fge쯪LH`A:Jgm۸O٠8/c/e@ )VovC]{ Veveq+K1rL':Xմ%@#drShRv::$"=a .8rkI(;oˏ|CMYu7T]".gg \M?YϒЀH߽WVCpsC>1 Ճy N2nndu&k ߂`Z6އ0YzӳrfzsHHO |&x:=T?dn IWB!B!B!Bھ7(data.tar.gz 1285863052 0 0 100644 1020 ` _Ec * R?G^L Y܉k.9 N6mv;^O}Q8ŗ""B/'"ȩ (g7rV'e2;7Z -+φQ \6 S<X3"\D);OQE-,CֶFհֿKmko);c7B`cƵQ_WjUuw<ا:;{__T6ߴ_HMӬ.:q{6n'(;o}Br?u%3`_\]gc0vyb|Oܻ4\y⅟ μ=_oa_[9ҫ3*YzsG]zr#/|'ݏ]ْvFnNr q:^]b ;SU !A B#w0( x2/F&(>9=y̡]:?9 4C `?u?2a'*U]Wِ>bѨ]W%GUj PCQ ͇.AG= 5+%x GLT; ?\|,h!fX8#>|!H<e ݨCC'ÑGzK@|y8iI(V+Ӎx`?1DB:"J%@#@niID8 0㉸2?]"D!o8D đ Z`ֲ[Ds j33F۞nAsƔݶ 1{jCnLca %QZoGA;G]ƢpGq IX**!v3?>]kDlg #YAa]o胢(bM0-:-4[Y{xMR|I$D"H$D"H$WԨ(chef-11.8.2/spec/data/lwrp/0000755000004100000410000000000012254362222015367 5ustar www-datawww-datachef-11.8.2/spec/data/lwrp/resources/0000755000004100000410000000000012254362222017401 5ustar www-datawww-datachef-11.8.2/spec/data/lwrp/resources/foo.rb0000644000004100000410000000007412254362222020512 0ustar www-datawww-dataactions :never_execute attribute :ever, :kind_of => String chef-11.8.2/spec/data/lwrp/resources/bar.rb0000644000004100000410000000006412254362222020472 0ustar www-datawww-dataactions :pass_buck, :prepare_eyes, :watch_paint_dry chef-11.8.2/spec/data/lwrp/providers/0000755000004100000410000000000012254362222017404 5ustar www-datawww-datachef-11.8.2/spec/data/lwrp/providers/embedded_resource_accesses_providers_scope.rb0000644000004100000410000000104612254362222030531 0ustar www-datawww-data# This action tests that embedded Resources have access to the enclosing Provider's # lexical scope (as demonstrated by the call to new_resource) and that all parameters # are passed properly (as demonstrated by the call to generate_new_name). attr_reader :enclosed_resource action :twiddle_thumbs do @enclosed_resource = lwrp_foo :foo do monkey generate_new_name(new_resource.monkey){ 'the monkey' } action :twiddle_thumbs provider :lwrp_monkey_name_printer end end def generate_new_name(str, &block) "#{str}, #{block.call}" end chef-11.8.2/spec/data/lwrp/providers/buck_passer.rb0000644000004100000410000000014512254362222022232 0ustar www-datawww-dataaction :buck_stops_here do log "This should be overwritten by ../lwrp_override/buck_passer.rb" end chef-11.8.2/spec/data/lwrp/providers/paint_drying_watcher.rb0000644000004100000410000000015112254362222024132 0ustar www-datawww-dataaction :prepare_eyes do "Prepared" end action :watch_paint_dry do "This isn't very interesting" end chef-11.8.2/spec/data/lwrp/providers/inline_compiler.rb0000644000004100000410000000067012254362222023104 0ustar www-datawww-data use_inline_resources action :test do ruby_block "interior-ruby-block-1" do block do # doesn't need to do anything end notifies :run, "ruby_block[interior-ruby-block-2]", :immediately end ruby_block "interior-ruby-block-2" do block do $interior_ruby_block_2 = "executed" end action :nothing end end action :no_updates do ruby_block "no-action" do block {} action :nothing end end chef-11.8.2/spec/data/lwrp/providers/monkey_name_printer.rb0000644000004100000410000000017012254362222023774 0ustar www-datawww-dataattr_reader :monkey_name action :twiddle_thumbs do @monkey_name = "my monkey's name is '#{new_resource.monkey}'" end chef-11.8.2/spec/data/lwrp/providers/buck_passer_2.rb0000644000004100000410000000035212254362222022453 0ustar www-datawww-dataaction :pass_buck do lwrp_bar :prepared_eyes do action :prepare_eyes provider :lwrp_paint_drying_watcher end lwrp_bar :dried_paint_watched do action :watch_paint_dry provider :lwrp_paint_drying_watcher end end chef-11.8.2/spec/data/lwrp/providers/thumb_twiddler.rb0000644000004100000410000000013612254362222022746 0ustar www-datawww-dataaction :prepare_thumbs do "Prepared" end action :twiddle_thumbs do "Twiddle twiddle" end chef-11.8.2/spec/data/lwrp/resources_with_default_attributes/0000755000004100000410000000000012254362222024406 5ustar www-datawww-datachef-11.8.2/spec/data/lwrp/resources_with_default_attributes/nodeattr.rb0000644000004100000410000000011012254362222026543 0ustar www-datawww-dataattribute :penguin, :kind_of => String, :default => node[:penguin_name] chef-11.8.2/spec/data/fileedit/0000755000004100000410000000000012254362222016170 5ustar www-datawww-datachef-11.8.2/spec/data/fileedit/blank0000644000004100000410000000000012254362222017170 0ustar www-datawww-datachef-11.8.2/spec/data/fileedit/hosts0000644000004100000410000000015412254362222017253 0ustar www-datawww-data127.0.0.1 localhost 255.255.255.255 broadcasthost ::1 localhost fe80::1%lo0 localhost chef-11.8.2/spec/data/old_home_dir/0000755000004100000410000000000012254362222017027 5ustar www-datawww-datachef-11.8.2/spec/data/old_home_dir/my-dot-emacs0000644000004100000410000000000012254362222021237 0ustar www-datawww-datachef-11.8.2/spec/data/old_home_dir/my-dot-vim0000644000004100000410000000000012254362222020742 0ustar www-datawww-datachef-11.8.2/spec/data/config.rb0000644000004100000410000000013712254362222016176 0ustar www-datawww-data# # Sample Chef Config File # cookbook_path "/etc/chef/cookbook", "/etc/chef/site-cookbook" chef-11.8.2/spec/data/object_loader/0000755000004100000410000000000012254362222017177 5ustar www-datawww-datachef-11.8.2/spec/data/object_loader/nodes/0000755000004100000410000000000012254362222020307 5ustar www-datawww-datachef-11.8.2/spec/data/object_loader/nodes/test.json0000644000004100000410000000010012254362222022150 0ustar www-datawww-data{ "name": "test", "environment": "prod", "run_list": [] } chef-11.8.2/spec/data/object_loader/nodes/test.rb0000644000004100000410000000003712254362222021613 0ustar www-datawww-dataname "test" environment "prod" chef-11.8.2/spec/data/object_loader/nodes/test_json_class.json0000644000004100000410000000013612254362222024377 0ustar www-datawww-data{ "name": "test", "json_class": "Chef::Node", "environment": "prod", "run_list": [] } chef-11.8.2/spec/data/object_loader/roles/0000755000004100000410000000000012254362222020323 5ustar www-datawww-datachef-11.8.2/spec/data/object_loader/roles/test.json0000644000004100000410000000010012254362222022164 0ustar www-datawww-data{ "name": "test", "description": "prod", "run_list": [] } chef-11.8.2/spec/data/object_loader/roles/test.rb0000644000004100000410000000003712254362222021627 0ustar www-datawww-dataname "test" description "prod" chef-11.8.2/spec/data/object_loader/roles/test_json_class.json0000644000004100000410000000013612254362222024413 0ustar www-datawww-data{ "name": "test", "json_class": "Chef::Role", "description": "prod", "run_list": [] } chef-11.8.2/spec/data/object_loader/environments/0000755000004100000410000000000012254362222021726 5ustar www-datawww-datachef-11.8.2/spec/data/object_loader/environments/test.json0000644000004100000410000000010012254362222023567 0ustar www-datawww-data{ "name": "test", "description": "prod", "run_list": [] } chef-11.8.2/spec/data/object_loader/environments/test.rb0000644000004100000410000000003712254362222023232 0ustar www-datawww-dataname "test" description "prod" chef-11.8.2/spec/data/object_loader/environments/test_json_class.json0000644000004100000410000000014512254362222026016 0ustar www-datawww-data{ "name": "test", "json_class": "Chef::Environment", "description": "prod", "run_list": [] } chef-11.8.2/spec/data/trusted_certs/0000755000004100000410000000000012254362222017275 5ustar www-datawww-datachef-11.8.2/spec/data/trusted_certs/opscode.pem0000644000004100000410000000450212254362222021435 0ustar www-datawww-data-----BEGIN CERTIFICATE----- MIIGqjCCBZKgAwIBAgIQCJlQhNSTz1z3zHZb972KvDANBgkqhkiG9w0BAQUFADBI MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSIwIAYDVQQDExlE aWdpQ2VydCBTZWN1cmUgU2VydmVyIENBMB4XDTEzMDQxMjAwMDAwMFoXDTE0MDYx NjEyMDAwMFowYzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAO BgNVBAcTB1NlYXR0bGUxFTATBgNVBAoTDE9wc2NvZGUsIEluYzEWMBQGA1UEAwwN Ki5vcHNjb2RlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN+U HLAzObPRlmchlkJ2JFeReJRPXj5F27HuX8SXT+5WhVGunQf1swjASJ0utk1x9wGT f9tnF8fYiwJIqWJopaPiwzNw1cD6CnIfhM3z4T3EzLAWWu2ZhfuaQk9Z6jhItkm7 upO4CsFq1xw7IjqOq09PCAklYC/Y/8Qq5Qj8VoTp0ldVv6hbqTNkezhWcKU/07si jAX1O+DYN6dlVNezfl4Xt5ccsu8Mp0s92IMVYLgY6bpb1b91ez9+XBE1v7zjaR0V EP7Ix9av/pXjqMqHgjlsg46UpLa30f4FEi2xmXpCBpOP94rCrT7g+u8UlIrJ/QK/ /lHyKBpCm0R9ftDbppsCAwEAAaOCA3MwggNvMB8GA1UdIwQYMBaAFJBx2zfrc8jv 3NUeErY0uitaoKaSMB0GA1UdDgQWBBTdhCU7MvQblxtWHlfHG4jPUTuh5DBLBgNV HREERDBCgg0qLm9wc2NvZGUuY29tggtvcHNjb2RlLmNvbYIQY29ycC5vcHNjb2Rl LmNvbYISKi5jb3JwLm9wc2NvZGUuY29tMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwYQYDVR0fBFowWDAqoCigJoYkaHR0cDov L2NybDMuZGlnaWNlcnQuY29tL3NzY2EtZzEuY3JsMCqgKKAmhiRodHRwOi8vY3Js NC5kaWdpY2VydC5jb20vc3NjYS1nMS5jcmwwggHEBgNVHSAEggG7MIIBtzCCAbMG CWCGSAGG/WwBATCCAaQwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cuZGlnaWNlcnQu Y29tL3NzbC1jcHMtcmVwb3NpdG9yeS5odG0wggFkBggrBgEFBQcCAjCCAVYeggFS AEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0AGgAaQBzACAAQwBlAHIAdABpAGYAaQBj AGEAdABlACAAYwBvAG4AcwB0AGkAdAB1AHQAZQBzACAAYQBjAGMAZQBwAHQAYQBu AGMAZQAgAG8AZgAgAHQAaABlACAARABpAGcAaQBDAGUAcgB0ACAAQwBQAC8AQwBQ AFMAIABhAG4AZAAgAHQAaABlACAAUgBlAGwAeQBpAG4AZwAgAFAAYQByAHQAeQAg AEEAZwByAGUAZQBtAGUAbgB0ACAAdwBoAGkAYwBoACAAbABpAG0AaQB0ACAAbABp AGEAYgBpAGwAaQB0AHkAIABhAG4AZAAgAGEAcgBlACAAaQBuAGMAbwByAHAAbwBy AGEAdABlAGQAIABoAGUAcgBlAGkAbgAgAGIAeQAgAHIAZQBmAGUAcgBlAG4AYwBl AC4weAYIKwYBBQUHAQEEbDBqMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp Y2VydC5jb20wQgYIKwYBBQUHMAKGNmh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNv bS9EaWdpQ2VydFNlY3VyZVNlcnZlckNBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqG SIb3DQEBBQUAA4IBAQCNk1+7l+VlAZrKov7ugP7WuKS7IEUZRk8CVAFPtIrp+jFB 6W0ta1qMpYyItp5enTBCGOkTfPly06hZnFRQw3ZnkSsWDKIvCRks4kZt3oHLd3nO G671JGRJI/qbs6F5l6c96kotlZkolYIPMhyK8Ex4LjMW6UrPWdpJrXTWPvLq4c85 ZaN52yKu6tsLrBTPwPmK9t+zQ2drb1g8Eq9B+cuwD3Row6njsDQ1Ltry+KCnivki E/ptgwyCkS4brkhjHMz5l5Co0KMsHylAb2XcBxFVFSl0aJIqK5Gr0nTlg26pNG7O qxv6ncOHl3tmArETi36TQbTYvFc+6cNb8CqdWe95 -----END CERTIFICATE----- chef-11.8.2/spec/data/trusted_certs/root.pem0000644000004100000410000000247212254362222020770 0ustar www-datawww-data-----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt 43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg 06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE----- chef-11.8.2/spec/data/trusted_certs/intermediate.pem0000644000004100000410000000315312254362222022454 0ustar www-datawww-data-----BEGIN CERTIFICATE----- MIIEjzCCA3egAwIBAgIQBp4dt3/PHfupevXlyaJANzANBgkqhkiG9w0BAQUFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaMEgxCzAJBgNVBAYTAlVT MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxIjAgBgNVBAMTGURpZ2lDZXJ0IFNlY3Vy ZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7V+Qh qdWbYDd+jqFhf4HiGsJ1ZNmRUAvkNkQkbjDSm3on+sJqrmpwCTi5IArIZRBKiKwx 8tyS8mOhXYBjWYCSIxzm73ZKUDXJ2HE4ue3w5kKu0zgmeTD5IpTG26Y/QXiQ2N5c fml9+JAVOtChoL76srIZodgr0c6/a91Jq6OS/rWryME+7gEA2KlEuEJziMNh9atK gygK0tRJ+mqxzd9XLJTl4sqDX7e6YlwvaKXwwLn9K9HpH9gaYhW9/z2m98vv5ttl LyU47PvmIGZYljQZ0hXOIdMkzNkUb9j+Vcfnb7YPGoxJvinyulqagSY3JG/XSBJs Lln1nBi72fZo4t9FAgMBAAGjggFaMIIBVjASBgNVHRMBAf8ECDAGAQH/AgEAMA4G A1UdDwEB/wQEAwIBhjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6 Ly9vY3NwLmRpZ2ljZXJ0LmNvbTB7BgNVHR8EdDByMDegNaAzhjFodHRwOi8vY3Js My5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290Q0EuY3JsMDegNaAzhjFo dHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290Q0EuY3Js MD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5k aWdpY2VydC5jb20vQ1BTMB0GA1UdDgQWBBSQcds363PI79zVHhK2NLorWqCmkjAf BgNVHSMEGDAWgBQD3lA1VtFMu2bwo+IbG8OXsj3RVTANBgkqhkiG9w0BAQUFAAOC AQEAMM7RlVEArgYLoQ4CwBestn+PIPZAdXQczHixpE/q9NDEnaLegQcmH0CIUfAf z7dMQJnQ9DxxmHOIlywZ126Ej6QfnFog41FcsMWemWpPyGn3EP9OrRnZyVizM64M 2ZYpnnGycGOjtpkWQh1l8/egHn3F1GUUsmKE1GxcCAzYbJMrtHZZitF//wPYwl24 LyLWOPD2nGt9RuuZdPfrSg6ppgTre87wXGuYMVqYQOtpxAX0IKjKCDplbDgV9Vws slXkLGtB8L5cRspKKaBIXiDSRf8F3jSvcEuBOeLKB1d8tjHcISnivpcOd5AUUUDh v+PMGxmcJcqnBrJT3yOyzxIZow== -----END CERTIFICATE----- chef-11.8.2/spec/data/trusted_certs/example.crt0000644000004100000410000000242212254362222021442 0ustar www-datawww-data-----BEGIN CERTIFICATE----- MIIDkjCCAnoCCQDihI8kxGYTFTANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMC VVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMRAwDgYDVQQKEwdZb3VD b3JwMRMwEQYDVQQLEwpPcGVyYXRpb25zMRYwFAYDVQQDEw1leGFtcGxlLmxvY2Fs MR0wGwYJKoZIhvcNAQkBFg5tZUBleGFtcGxlLmNvbTAeFw0xMzEwMTcxODAxMzVa Fw0yMzEwMTUxODAxMzVaMIGKMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAO BgNVBAcTB1NlYXR0bGUxEDAOBgNVBAoTB1lvdUNvcnAxEzARBgNVBAsTCk9wZXJh dGlvbnMxFjAUBgNVBAMTDWV4YW1wbGUubG9jYWwxHTAbBgkqhkiG9w0BCQEWDm1l QGV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyKBo U+Bdni0xZK/NCzdLdi2X+TyW5eahbYMx+r1GDcVqCICvrthBCVLVFsQ8rvOHwTPi AxQJGxb9TLSXRgXQSlH6FLjIUceuOtpan3qYVJ1v7AxY4DgNvYBpbtJz5MQedJnT g2F+rXzkwaD6CWBqWHeGU0oP3r7bq1AMD6XEsK2w2/zHtG7TEnL45ARv1PsyrU5M ZAW/XyoMyq1k2Lpv7YR5kAvTq1+4RSt/it2RFE7R0AVbaQ0MeAnllfySiHHHlaOT FVd/qPSiGISxsUmmzA3Z08+0sfJwkrnJXbLscCBYndd7gMGgtczGjJtul0Ch3GFa /Pn5McjwF272+usJ1wIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQCzPePWifWNECsG nL8on1AtFMkczE1/pdRS4YUl/Tc926MpezptSja8rL31+4Bom37/wYPG7HygtAQl R4FHpAtuqJKPOfjUmDNsIXRFnytrnflTpctDu/Nbj4PDCy01k/sTDUQt+s+lEBL8 M8ArmfLZ8PCfAwnXmJQ5rggDFKqegjt6z1RsSglbMiASE7+KkpBnzaqH6fET6IQz WgAjv6WdRfwgfJjOTSX4XMpCSet9KaWmXExKrxiVng2Uu6E+ShVAyKaGMuc1B7VA oxnnVaVapFv5lOWucQr4KkC7EgaUZnyt8duOc8+Yvd+y3Xd2dcHUnmegRxly4jRV /lXbFAUb -----END CERTIFICATE----- chef-11.8.2/spec/data/file-providers-method-snapshot-chef-11-4.json0000644000004100000410000000560112254362222024630 0ustar www-datawww-data{ "Chef::Provider::CookbookFile": [ "action_create", "file_cache_location", "resource_cookbook", "backup_new_resource", "content_stale?", "diff_current_from_content", "is_binary?", "diff_current", "setup_acl", "compare_content", "set_content", "update_new_file_state", "set_all_access_controls", "action_create_if_missing", "action_delete", "action_touch", "backup", "deploy_tempfile", "shell_out", "shell_out!", "run_command_compatible_options", "checksum", "access_controls", "enforce_ownership_and_permissions" ], "Chef::Provider::RemoteFile": [ "action_create", "current_resource_matches_target_checksum?", "matches_current_checksum?", "backup_new_resource", "source_file", "http_client_opts", "diff_current_from_content", "is_binary?", "diff_current", "setup_acl", "compare_content", "set_content", "update_new_file_state", "set_all_access_controls", "action_create_if_missing", "action_delete", "action_touch", "backup", "deploy_tempfile", "shell_out", "shell_out!", "run_command_compatible_options", "checksum", "access_controls", "enforce_ownership_and_permissions" ], "Chef::Provider::Template": [ "action_create", "template_finder", "template_location", "resource_cookbook", "rendered", "content_matches?", "render_template", "diff_current_from_content", "is_binary?", "diff_current", "setup_acl", "compare_content", "set_content", "update_new_file_state", "set_all_access_controls", "action_create_if_missing", "action_delete", "action_touch", "backup", "deploy_tempfile", "shell_out", "shell_out!", "run_command_compatible_options", "checksum", "access_controls", "enforce_ownership_and_permissions" ], "Chef::Provider::Directory": [ "action_create", "action_delete", "diff_current_from_content", "is_binary?", "diff_current", "setup_acl", "compare_content", "set_content", "update_new_file_state", "set_all_access_controls", "action_create_if_missing", "action_touch", "backup", "deploy_tempfile", "shell_out", "shell_out!", "run_command_compatible_options", "checksum", "access_controls", "enforce_ownership_and_permissions" ], "Chef::Provider::File": [ "diff_current_from_content", "is_binary?", "diff_current", "setup_acl", "compare_content", "set_content", "update_new_file_state", "action_create", "set_all_access_controls", "action_create_if_missing", "action_delete", "action_touch", "backup", "deploy_tempfile", "shell_out", "shell_out!", "run_command_compatible_options", "checksum", "access_controls", "enforce_ownership_and_permissions" ] } chef-11.8.2/spec/data/checksum_cache/0000755000004100000410000000000012254362222017330 5ustar www-datawww-datachef-11.8.2/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ufy6g3-00000644000004100000410000000002312254362222031031 0ustar www-datawww-datachecksum data here chef-11.8.2/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-600hhz-00000644000004100000410000000002312254362222030725 0ustar www-datawww-datachecksum data here chef-11.8.2/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-el14l6-00000644000004100000410000000002312254362222030715 0ustar www-datawww-datachecksum data here chef-11.8.2/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-t8g0sv-00000644000004100000410000000002312254362222031041 0ustar www-datawww-datachecksum data here chef-11.8.2/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ahd2gq-00000644000004100000410000000002312254362222031054 0ustar www-datawww-datachecksum data here chef-11.8.2/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-api8ux-00000644000004100000410000000002312254362222031124 0ustar www-datawww-datachecksum data here chef-11.8.2/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-x2d6j9-00000644000004100000410000000002312254362222030734 0ustar www-datawww-datachecksum data here chef-11.8.2/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-kkbs85-00000644000004100000410000000002312254362222031015 0ustar www-datawww-datachecksum data here chef-11.8.2/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-t7k1g-00000644000004100000410000000002312254362222030643 0ustar www-datawww-datachecksum data here chef-11.8.2/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ra8uim-00000644000004100000410000000002312254362222031113 0ustar www-datawww-datachecksum data here chef-11.8.2/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ory1ux-00000644000004100000410000000002312254362222031155 0ustar www-datawww-datachecksum data here chef-11.8.2/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-bfygsi-00000644000004100000410000000002312254362222031171 0ustar www-datawww-datachecksum data here chef-11.8.2/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-6m8zdk-00000644000004100000410000000000012254362222031024 0ustar www-datawww-datachef-11.8.2/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-b0r1m1-00000644000004100000410000000002312254362222030710 0ustar www-datawww-datachecksum data here chef-11.8.2/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-xi0l6h-00000644000004100000410000000002312254362222031020 0ustar www-datawww-datachecksum data here chef-11.8.2/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ivrl3y-00000644000004100000410000000002312254362222031136 0ustar www-datawww-datachecksum data here chef-11.8.2/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-pgsq76-00000644000004100000410000000002312254362222031035 0ustar www-datawww-datachecksum data here chef-11.8.2/spec/data/cookbooks/0000755000004100000410000000000012254362222016374 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/angrybash/0000755000004100000410000000000012254362222020352 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/angrybash/recipes/0000755000004100000410000000000012254362222022004 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/angrybash/recipes/default.rb0000644000004100000410000000036312254362222023757 0ustar www-datawww-databash "go off the rails" do code <<-END for i in localhost 127.0.0.1 #{Socket.gethostname()} do echo "grant all on *.* to root@'$i' identified by 'a_password'; flush privileges;" | mysql -u root -h 127.0.0.1 done END end chef-11.8.2/spec/data/cookbooks/openldap/0000755000004100000410000000000012254362222020176 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/openldap/definitions/0000755000004100000410000000000012254362222022511 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/openldap/definitions/client.rb0000644000004100000410000000016412254362222024315 0ustar www-datawww-datadefine :openldap_client, :mothra => "a big monster" do cat "#{params[:name]}" do pretty_kitty true end end chef-11.8.2/spec/data/cookbooks/openldap/definitions/server.rb0000644000004100000410000000016412254362222024345 0ustar www-datawww-datadefine :openldap_server, :mothra => "a big monster" do cat "#{params[:name]}" do pretty_kitty true end end chef-11.8.2/spec/data/cookbooks/openldap/files/0000755000004100000410000000000012254362222021300 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/openldap/files/default/0000755000004100000410000000000012254362222022724 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/openldap/files/default/remotedir/0000755000004100000410000000000012254362222024716 5ustar www-datawww-data././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootchef-11.8.2/spec/data/cookbooks/openldap/files/default/remotedir/subdir_with_no_file_just_a_subsubdir/chef-11.8.2/spec/data/cookbooks/openldap/files/default/remotedir/subdir_with_no_file_just_a_subsubdi0000755000004100000410000000000012254362222034122 5ustar www-datawww-data././@LongLink0000000000000000000000000000016500000000000011567 Lustar rootrootchef-11.8.2/spec/data/cookbooks/openldap/files/default/remotedir/subdir_with_no_file_just_a_subsubdir/the_subsubdir/chef-11.8.2/spec/data/cookbooks/openldap/files/default/remotedir/subdir_with_no_file_just_a_subsubdi0000755000004100000410000000000012254362222034122 5ustar www-datawww-data././@LongLink0000000000000000000000000000020200000000000011557 Lustar rootrootchef-11.8.2/spec/data/cookbooks/openldap/files/default/remotedir/subdir_with_no_file_just_a_subsubdir/the_subsubdir/some_file.txtchef-11.8.2/spec/data/cookbooks/openldap/files/default/remotedir/subdir_with_no_file_just_a_subsubdi0000644000004100000410000000020512254362222034121 0ustar www-datawww-data# remote directory # file specificity: default # relpath: remotedir/subdir_with_no_file_just_a_subsubdir/the_subsubdir/some_file.txt chef-11.8.2/spec/data/cookbooks/openldap/files/default/remotedir/.a_dotdir/0000755000004100000410000000000012254362222026561 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/openldap/files/default/remotedir/.a_dotdir/.a_dotfile_in_a_dotdir0000644000004100000410000000003612254362222033042 0ustar www-datawww-datathis is a dotfile in a dotdir chef-11.8.2/spec/data/cookbooks/openldap/files/default/remotedir/remote_dir_file2.txt0000644000004100000410000000013012254362222030663 0ustar www-datawww-data# remote directory # file specificity: default # relpath: remotedir/remote_dir_file2.txtchef-11.8.2/spec/data/cookbooks/openldap/files/default/remotedir/remote_dir_file1.txt0000644000004100000410000000013012254362222030662 0ustar www-datawww-data# remote directory # file specificity: default # relpath: remotedir/remote_dir_file1.txtchef-11.8.2/spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/0000755000004100000410000000000012254362222027422 5ustar www-datawww-data././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootchef-11.8.2/spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/remote_subdir_file1.txtchef-11.8.2/spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/remote_subdir_file1.tx0000644000004100000410000000014512254362222033722 0ustar www-datawww-data# remote directory # file specificity: default # relpath: remotedir/remotesubdir/remote_dir_file1.txt././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootchef-11.8.2/spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/remote_subdir_file2.txtchef-11.8.2/spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/remote_subdir_file2.tx0000644000004100000410000000014512254362222033723 0ustar www-datawww-data# remote directory # file specificity: default # relpath: remotedir/remotesubdir/remote_dir_file2.txtchef-11.8.2/spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/.a_dotfile0000644000004100000410000000006212254362222031347 0ustar www-datawww-datathis is a file with a name beginning with a . dot chef-11.8.2/spec/data/cookbooks/openldap/files/default/.ssh/0000755000004100000410000000000012254362222023577 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/openldap/files/default/.ssh/id_rsa0000644000004100000410000000001012254362222024752 0ustar www-datawww-dataFAKE KEYchef-11.8.2/spec/data/cookbooks/openldap/files/default/.dotfile0000644000004100000410000000006612254362222024355 0ustar www-datawww-dataI am here to test .dotfiles work in file directories. chef-11.8.2/spec/data/cookbooks/openldap/templates/0000755000004100000410000000000012254362222022174 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/openldap/templates/default/0000755000004100000410000000000012254362222023620 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/openldap/templates/default/helpers_via_partial_test.erb0000644000004100000410000000004712254362222031367 0ustar www-datawww-data<%= render("helper_test.erb").strip %> chef-11.8.2/spec/data/cookbooks/openldap/templates/default/openldap_variable_stuff.conf.erb0000644000004100000410000000004012254362222032106 0ustar www-datawww-datasuper secret is <%= @secret -%> chef-11.8.2/spec/data/cookbooks/openldap/templates/default/helper_test.erb0000644000004100000410000000002512254362222026625 0ustar www-datawww-data<%= helper_method %> chef-11.8.2/spec/data/cookbooks/openldap/templates/default/openldap_stuff.conf.erb0000644000004100000410000000004712254362222030250 0ustar www-datawww-dataslappiness is <%= node[:slappiness] -%>chef-11.8.2/spec/data/cookbooks/openldap/templates/default/no_windows_line_endings.erb0000644000004100000410000000010412254362222031211 0ustar www-datawww-dataTemplate rendering libraries should support different line endings chef-11.8.2/spec/data/cookbooks/openldap/templates/default/some_windows_line_endings.erb0000644000004100000410000000010612254362222031542 0ustar www-datawww-dataTemplate rendering libraries should support different line endings chef-11.8.2/spec/data/cookbooks/openldap/templates/default/all_windows_line_endings.erb0000644000004100000410000000011012254362222031342 0ustar www-datawww-dataTemplate rendering libraries should support different line endings chef-11.8.2/spec/data/cookbooks/openldap/templates/default/test.erb0000644000004100000410000000003712254362222025271 0ustar www-datawww-dataWe could be diving for pearls! chef-11.8.2/spec/data/cookbooks/openldap/metadata.rb0000644000004100000410000000065412254362222022310 0ustar www-datawww-dataname "openldap" maintainer "Opscode, Inc." maintainer_email "cookbooks@opscode.com" license "Apache 2.0" description "Installs and configures all aspects of openldap using Debian style symlinks with helper definitions" long_description "The long description for the openldap cookbook from metadata.rb" version "8.9.10" recipe "openldap", "Main Open LDAP configuration" chef-11.8.2/spec/data/cookbooks/openldap/attributes/0000755000004100000410000000000012254362222022364 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/openldap/attributes/default.rb0000644000004100000410000000073512254362222024342 0ustar www-datawww-datachef_env ||= nil case chef_env when "prod" default[:ldap_server] = "ops1prod" default[:ldap_basedn] = "dc=hjksolutions,dc=com" default[:ldap_replication_password] = "yes" when "corp" default[:ldap_server] = "ops1prod" default[:ldap_basedn] = "dc=hjksolutions,dc=com" default[:ldap_replication_password] = "yougotit" else default[:ldap_server] = "ops1prod" default[:ldap_basedn] = "dc=hjksolutions,dc=com" default[:ldap_replication_password] = "forsure" end chef-11.8.2/spec/data/cookbooks/openldap/attributes/smokey.rb0000644000004100000410000000003612254362222024217 0ustar www-datawww-datadefault[:smokey] = "robinson" chef-11.8.2/spec/data/cookbooks/openldap/recipes/0000755000004100000410000000000012254362222021630 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/openldap/recipes/default.rb0000644000004100000410000000005112254362222023575 0ustar www-datawww-datacat "blanket" do pretty_kitty true end chef-11.8.2/spec/data/cookbooks/openldap/recipes/one.rb0000644000004100000410000000035212254362222022736 0ustar www-datawww-data## # Nodes should have a unique name ## name "test.example.com-default" ## # Nodes can set arbitrary arguments ## sunshine "in" something "else" ## # Nodes should have recipes ## recipes "operations-master", "operations-monitoring" chef-11.8.2/spec/data/cookbooks/openldap/recipes/gigantor.rb0000644000004100000410000000005212254362222023764 0ustar www-datawww-datacat "blanket" do pretty_kitty false end chef-11.8.2/spec/data/cookbooks/java/0000755000004100000410000000000012254362222017315 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/java/files/0000755000004100000410000000000012254362222020417 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/java/files/default/0000755000004100000410000000000012254362222022043 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/java/files/default/java.response0000644000004100000410000000013412254362222024542 0ustar www-datawww-data# Hi, I'm pretending to be the preseed file for installing the Sun JDK on debian # or Ubuntuchef-11.8.2/spec/data/cookbooks/borken/0000755000004100000410000000000012254362222017654 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/borken/templates/0000755000004100000410000000000012254362222021652 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/borken/templates/default/0000755000004100000410000000000012254362222023276 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/borken/templates/default/borken.erb0000644000004100000410000000012312254362222025244 0ustar www-datawww-dataa cat walked on the keyboard one day... <%= (*&)(*^^^^*******++_+_--- }}}}]]]end)%>chef-11.8.2/spec/data/cookbooks/borken/recipes/0000755000004100000410000000000012254362222021306 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/borken/recipes/default.rb0000644000004100000410000000013412254362222023255 0ustar www-datawww-dataa cat walked on the keyboard one day... (*&(*&(*&(*&(*^%$%^%#^^&(*)(*{}}}}}}}}+++++===))))))chef-11.8.2/spec/data/cookbooks/chefignore0000644000004100000410000000026112254362222020427 0ustar www-datawww-data# # The ignore file allows you to skip files in cookbooks with the same name that appear # later in the search path. # recipes/ignoreme.rb # comments can be indented ignored chef-11.8.2/spec/data/cookbooks/ignorken/0000755000004100000410000000000012254362222020210 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/ignorken/recipes/0000755000004100000410000000000012254362222021642 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/ignorken/recipes/default.rb0000644000004100000410000000001712254362222023611 0ustar www-datawww-data# This is fine!chef-11.8.2/spec/data/cookbooks/ignorken/recipes/ignoreme.rb0000644000004100000410000000013412254362222023772 0ustar www-datawww-dataa cat walked on the keyboard one day... (*&(*&(*&(*&(*^%$%^%#^^&(*)(*{}}}}}}}}+++++===))))))chef-11.8.2/spec/data/cookbooks/preseed/0000755000004100000410000000000012254362222020023 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/preseed/files/0000755000004100000410000000000012254362222021125 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/preseed/files/default/0000755000004100000410000000000012254362222022551 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/preseed/files/default/preseed-template.seed0000644000004100000410000000042112254362222026650 0ustar www-datawww-data# This file should never be executed by the preseeding tests # This is here to verify that templates are preferred over cookbook_files when # preseeding packages. chef-integration-test chef-integration-test/sample-var string "WRONG-cookbook file used instead of template!" chef-11.8.2/spec/data/cookbooks/preseed/files/default/preseed-file.seed0000644000004100000410000000011412254362222025753 0ustar www-datawww-datachef-integration-test chef-integration-test/sample-var string "hello world" chef-11.8.2/spec/data/cookbooks/preseed/templates/0000755000004100000410000000000012254362222022021 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/preseed/templates/default/0000755000004100000410000000000012254362222023445 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/preseed/templates/default/preseed-template.seed0000644000004100000410000000013512254362222027546 0ustar www-datawww-datachef-integration-test chef-integration-test/sample-var string "<%= node[:preseed_value] -%>" chef-11.8.2/spec/data/cookbooks/apache2/0000755000004100000410000000000012254362222017677 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/apache2/files/0000755000004100000410000000000012254362222021001 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/apache2/files/default/0000755000004100000410000000000012254362222022425 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/apache2/files/default/apache2_module_conf_generate.pl0000644000004100000410000000010012254362222030500 0ustar www-datawww-data# apache2_module_conf_generate.pl # this is just here for show. chef-11.8.2/spec/data/cookbooks/apache2/recipes/0000755000004100000410000000000012254362222021331 5ustar www-datawww-datachef-11.8.2/spec/data/cookbooks/apache2/recipes/default.rb0000644000004100000410000000003212254362222023275 0ustar www-datawww-data# # Nothing ot see here # chef-11.8.2/spec/data/lwrp_const_scoping/0000755000004100000410000000000012254362222020317 5ustar www-datawww-datachef-11.8.2/spec/data/lwrp_const_scoping/resources/0000755000004100000410000000000012254362222022331 5ustar www-datawww-datachef-11.8.2/spec/data/lwrp_const_scoping/resources/conflict.rb0000644000004100000410000000000012254362222024445 0ustar www-datawww-datachef-11.8.2/spec/data/git_bundles/0000755000004100000410000000000012254362222016702 5ustar www-datawww-datachef-11.8.2/spec/data/git_bundles/sinatra-test-app-with-symlinks.gitbundle0000644000004100000410000000443212254362222026620 0ustar www-datawww-data# v2 git bundle 5a4748c52aaea8250b4346a9b8ede95ee3755e28 refs/heads/master PACKxM @= h$x) )+|_`j-tuTcx]0'5&gfOX \mBLѦiSQGYMm 'G3;\ܒV=**wo5A:̭SP?CIxAn hW1GJpD|73,%LݓEG"'G:(`n'ܹQ-XOi 1Hv=ի|ϗ`M·~~HY>Iop[t1ÇM֚E64 ,vϦKa*hK\ZQ1xA @=:2' U\[AjCn?, H/$9hP]d"YWR*&wS(qY1qAN!VB$P}@sVyJ~5KS~!a 7DW3Ύ6*|dO vv iCLx !bаH%'@Zs&3k0ÆDKAv} DNڜAt\(->:1>i}d3 Ze~ zI'X?j/y ԻyIG xQ =^EcJU>dn_'4"l(ٮ x340031QpOMIe~'y06ww7DQz` ٽZ%U WG_W[>r'˞Sߺ($0P(<۝ϋӸKwKٜ̼bl5w*sWF>xKOUP*K,)JT$xswRP(.HM.24 L 5E%%y 9#=D,K,)JI#K+h)EulA,`F0̜ P!rP7 `\QiR%k+H:.zQ:x=AK1zz+Rċ9Κ$M&{'X0住fap|} ;<(R( VM *Tb͎8OSgG54+d ;dsi{jYQ̹rVS9, )O\88ʾJÑ I۾ׯťZ?t^Fx340031QH,(+Jb,ZqdH{++o|M Wx1 НS8L&be4ysG]PBgM_fp |rρG<&[bGx342 WG_W̼l+y/fYؽe{=ղ`޷exccP%3d9.hȷ.M x340031QH,(+Jb]QbߺFm7e[ǯ x10НStLEkLB[CRWFtJ7p&>5)#?k1 zF3xccP%2}.ilPXl= Qx340031QH,(+Jb˪wꕭ?5]gtWZK x10НStL$V@ϯ1y n EKsFtjF_pMK|j*EXOٛI Kl ΛĚchef-11.8.2/spec/data/git_bundles/sinatra-test-app-with-callback-files.gitbundle0000644000004100000410000000670712254362222027612 0ustar www-datawww-data# v2 git bundle 2404d015882659754bdb93ad6e4b4d3d02691a82 refs/heads/with-deploy-scripts PACK&x[jD!D]Eo`B;>Z! J_mɝQ"$XDw|6"Ps0%:dYb)8&6#G.Iz*rJM_Բ|z6/8-ܐ^_u-Jۄzzʮې yaQMxMn! @=IUիY|Tb`Dkj|fFPY둑ǜ\ɺo4)שm6>w;'8.%tFkKim :Z?'+pi{?NxxAn hW1GJpD|73,%LݓEG"'G:(`n'ܹQ-XOi 1Hv=ի|ϗ`M·~~HY>Iop[t1ÇM֚E64 ,vϦKa*hK\ZQ1xA @=:2' U\[AjCn?, H/$9hP]d"YWR*&wS(qY1qAN!VB$P}@sVyJ~5KS~!a 7DW3Ύ6*|dO vv iCLx !bаH%'@Zs&3k0ÆDKAv} DNڜAt\(->:1>i}d3 Ze~ zI'X?j/y ԻyIG xQ =^EcJU>dn_'4"l(ٯ x340031QpOMIe~'y06ww7DQz` ٽZ%U WG_W[>r'˞Sߺ($0m1Y:A?' wȦW2zxnyڎW"VG>xKOUP*K,)JT$xswRP(.HM.24 L 5E%%y 9#=D,K,)JI#K+h)EulA,`F0̜ P!rP7 `\QiR%k+H:.zQ:x=AK1zz+Rċ9Κ$M&{'X0住fap|} ;<(R( VM *Tb͎8OSgG54+d ;dsi{jYQ̹rVS9, )O\88ʾJÑ I۾ׯťZ?t^Fx340031QH,(+JbXEh 3?L xK 0 :Ûl=jY5Yy0.[]MSPU'QSQjFcWڝkf' 0?I/' x340031QHL+I-/J-.I,*+Jb2UM:ƻbMSm^.IiEE% I 525Nx ]f0ob$ ʱ/@P65+ss2AĒ?M=਴sF;Cx A нt2#Dw~AUdEVСy([,ſHZ ˆI5FxSV((OQ(/IQHJU(HU(JIM,N/H,JIUPRv,*OJM/JL/J,I+JRg?TjOxssZRQox A нtP뭟yYmHAi!f!=ۮo1CFXLJϛ֘|xSV((OQ(/IQHJU(HU(JIM,N/H,JIUPRv,*OJM/J/+(Qwx[ϸqB糞Emڹ>Gs f PHI-ɯdxD6 {&Nj=~;-Fzx340031QH,(+JbP \ZؿwAskIx+.˜6f x340031QHL+I-/J-.I,*+Jb\eڰO7r_\bQ_^X R,Skջ&OATH&;l޽/gausȅ7QWde?Ur2=s! rv|ƔF ixxR jdxccP%3d9.hȷ.M x340031QH,(+Jb]QbߺFm7e[ǯ x10НStLEkLB[CRWFtJ7p&>5)#?k1 zF3xccP%2}.ilPXl= Qx340031QH,(+Jb˪wꕭ?5]gtWZK x10НStL$V@ϯ1y n EKsFtjF_pMK|j*EXOٛI K^-;dd*6pchef-11.8.2/spec/data/git_bundles/example-repo.gitbundle0000644000004100000410000000227612254362222023206 0ustar www-datawww-data# v2 git bundle bc5ec79931ae74089aeadca6edc173527613e6d9 refs/heads/foo123 d294fbfd05aa7709ad9a9b8ef6343b17d355bf5f refs/heads/master 9b73fb5e316bfaff7b822b0ccb3e1e08f9885085 refs/tags/v1.0.0 d294fbfd05aa7709ad9a9b8ef6343b17d355bf5f HEAD PACK x 0 $MS !^,vHF!OWyUlea_ŷLBDkM\Ž>@+eib^gbkwc;ppXs Ry3;C?f]Asf~CQ x 0 @{ n"!ĉI\6U+p|FW" 1*vvb]1jS`9U"Km@\ϥhqifj"!|:t,Oi܎3m?Jz-mEͩ{ 4sk [,^=@& x 0 @{ 'O#!ĉ q\Z6Uk+p|t*ql@nJ:b4U*TLH8"q& .EK[6S%:|p;x}=f`B4.C cB{ x 0 @{H0HUSH+p/+}W)"Tr'Hc*URwxHQ(/IQ$}2űթt`$chef-11.8.2/spec/data/git_bundles/sinatra-test-app.gitbundle0000644000004100000410000000400512254362222023774 0ustar www-datawww-data# v2 git bundle 3eb5ca6c353c83d9179dd3b29347539829b401f3 refs/heads/master PACKxAn hW1GJpD|73,%LݓEG"'G:(`n'ܹQ-XOi 1Hv=ի|ϗ`M·~~HY>Iop[t1ÇM֚E64 ,vϦKa*hK\ZQ1xA @=:2' U\[AjCn?, H/$9hP]d"YWR*&wS(qY1qAN!VB$P}@sVyJ~5KS~!a 7DW3Ύ6*|dO vv iCLx !bаH%'@Zs&3k0ÆDKAv} DNڜAt\(->:1>i}d3 Ze~ zI'X?j/y ԻyIG xQ =^EcJU>dn_'4"l(ٮx340031QpOMIe~'y06ww7DQz` ٽZ%U WG_W[>r'˞Sߺ($0P(<۝ϋӸKwK8>xKOUP*K,)JT$xswRP(.HM.24 L 5E%%y 9#=D,K,)JI#K+h)EulA,`F0̜ P!rP7 `\QiR%k+H:.zQ:x=AK1zz+Rċ9Κ$M&{'X0住fap|} ;<(R( VM *Tb͎8OSgG54+d ;dsi{jYQ̹rVS9, )O\88ʾJÑ I۾ׯťZ?t^Fx340031QH,(+Jb,ZqdH{++o|M Wx1 НS8L&be4ysG]PBgM_fp |rρG<&[bGx340031QpOMIe~'y06ww7DQz` ٽZ%U WG_W;[Oسm[͓&@XP`g%~ҕi+?V06:f*x[qw ,x340031QH,(+JbHa:Hݏ{mŘ x10FSaHV@ocޏTH#O%v5tx5Ҧc;}>xccP%3d9.hȷ.M x340031QH,(+Jb]QbߺFm7e[ǯ x10НStLEkLB[CRWFtJ7p&>5)#?k1 zF3xccP%2}.ilPXl= Qx340031QH,(+Jb˪wꕭ?5]gtWZK x10НStL$V@ϯ1y n EKsFtjF_pMK|j*EXOٛI KTND;N#Y븬chef-11.8.2/spec/data/knife-site-subcommands/0000755000004100000410000000000012254362222020752 5ustar www-datawww-datachef-11.8.2/spec/data/knife-site-subcommands/plugins/0000755000004100000410000000000012254362222022433 5ustar www-datawww-datachef-11.8.2/spec/data/knife-site-subcommands/plugins/knife/0000755000004100000410000000000012254362222023527 5ustar www-datawww-datachef-11.8.2/spec/data/knife-site-subcommands/plugins/knife/example_subcommand.rb0000644000004100000410000000000012254362222027705 0ustar www-datawww-datachef-11.8.2/spec/data/big_json_plus_one.json0000644000004100000410000000456012254362222021001 0ustar www-datawww-data{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":{"key":"test" }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} chef-11.8.2/spec/data/knife-home/0000755000004100000410000000000012254362222016425 5ustar www-datawww-datachef-11.8.2/spec/data/knife-home/.chef/0000755000004100000410000000000012254362222017410 5ustar www-datawww-datachef-11.8.2/spec/data/knife-home/.chef/plugins/0000755000004100000410000000000012254362222021071 5ustar www-datawww-datachef-11.8.2/spec/data/knife-home/.chef/plugins/knife/0000755000004100000410000000000012254362222022165 5ustar www-datawww-datachef-11.8.2/spec/data/knife-home/.chef/plugins/knife/example_home_subcommand.rb0000644000004100000410000000000012254362222027353 0ustar www-datawww-datachef-11.8.2/spec/data/checksum/0000755000004100000410000000000012254362222016205 5ustar www-datawww-datachef-11.8.2/spec/data/checksum/random.txt0000644000004100000410000000200012254362222020216 0ustar www-datawww-datae4010abcac515ef3b78e92ee1f848a0d3bc3a526fcb826e7b4d39a6d516aa0487085c9b1be35e8d909617b250dca36dd4a55f01b7cdd310826bfd748cb27e0e43dd52b22968383c8086b06ee2d16e13574f98c058ce2bc3475b92ecf9c16e504022d60b132643986a8e7908d067526e20b4bafe1eb75349f27a4d3de02b077e76a2f59b73c14413f11e7208ae0bf6a408d51a97d490530e23476960ab8780ad86349947d82f1c9e57c85f86d71f80a6709b58be5f993a6a6df80c5a0857627d4a01e71484f6a6e983985089c00fe538e947230813c3a3e19baf6dae6db7082d07392a239ec1be385646356db3e3d76571488a6c72f0b96997f6191beea9846fc99f82a828f05af95cfc234cf681002f830915b1f3d35b2178b54a861c05d2694c5f6cfeb613a4a3670d849180461cdedf2c3cbb022608d8b19c86179d2d6da6b9acefccfc34b59663ef1282fec262bef79b2fbdd9b6669c90d6817b3762164dc309616469b33b83b1ded3420ae9177bc8f456d83939ff3c91b0a3683f3157401ceadf679c9f876da2aa413e081ee4c41d4b04f49e0c254d0082fd9bf2cb8eb8b966285be2cdcaab0ab70ea970737244b6683283598c30bdc206a05df72048b342eb40c2cd750c815d5fa944167b103ec40d60a99c49941a9e76d874149524f35ca294d081cf221757df77e027640556d983978be6b4b51aff26cd74a2f300d71chef-11.8.2/spec/data/partial_one.erb0000644000004100000410000000012212254362222017365 0ustar www-datawww-datapartial one <%= render('test.erb', :cookbook => 'openldap').strip %> calling home chef-11.8.2/spec/data/recipes/0000755000004100000410000000000012254362222016035 5ustar www-datawww-datachef-11.8.2/spec/data/recipes/test.rb0000644000004100000410000000014312254362222017337 0ustar www-datawww-data file "/etc/nsswitch.conf" do action :create owner "root" group "root" mode 0644 end chef-11.8.2/spec/rcov.opts0000644000004100000410000000004112254362222015345 0ustar www-datawww-data--exclude spec,bin,/Library/Ruby chef-11.8.2/spec/spec_helper.rb0000644000004100000410000001467212254362222016322 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # If you need to add anything in here, don't. # Add it to one of the files in spec/support # Configure this first so it doesn't trigger annoying warning when we use it. # Main rspec configuration comes later RSpec.configure do |config| config.treat_symbols_as_metadata_keys_with_true_values = true end # Abuse ruby's constant lookup to avoid undefined constant errors module Shell JUST_TESTING_MOVE_ALONG = true unless defined? JUST_TESTING_MOVE_ALONG IRB = nil unless defined? IRB end # Ruby 1.9 Compat $:.unshift File.expand_path("../..", __FILE__) require 'rubygems' require 'rspec/mocks' $:.unshift(File.join(File.dirname(__FILE__), "..", "lib")) $:.unshift(File.expand_path("../lib", __FILE__)) $:.unshift(File.dirname(__FILE__)) if ENV["COVERAGE"] require 'simplecov' SimpleCov.start do add_filter "/spec/" add_group "Remote File", "remote_file" add_group "Resources", "/resource/" add_group "Providers", "/provider/" add_group "Knife", "knife" end end require 'chef' require 'chef/knife' Dir['lib/chef/knife/**/*.rb']. map {|f| f.gsub('lib/', '') }. map {|f| f.gsub(%r[\.rb$], '') }. each {|f| require f } require 'chef/mixins' require 'chef/dsl' require 'chef/application' require 'chef/applications' require 'chef/shell' require 'chef/util/file_edit' require 'chef/config' # If you want to load anything into the testing environment # without versioning it, add it to spec/support/local_gems.rb require 'spec/support/local_gems.rb' if File.exists?(File.join(File.dirname(__FILE__), 'support', 'local_gems.rb')) # Explicitly require spec helpers that need to load first require 'spec/support/platform_helpers' # Autoloads support files # Excludes support/platforms by default # Do not change the gsub. Dir["spec/support/**/*.rb"]. reject { |f| f =~ %r{^spec/support/platforms} }. map { |f| f.gsub(%r{.rb$}, '') }. map { |f| f.gsub(%r[spec/], '')}. each { |f| require f } OHAI_SYSTEM = Ohai::System.new OHAI_SYSTEM.require_plugin("os") OHAI_SYSTEM.require_plugin("platform") TEST_PLATFORM = OHAI_SYSTEM["platform"].dup.freeze TEST_PLATFORM_VERSION = OHAI_SYSTEM["platform_version"].dup.freeze RSpec.configure do |config| config.include(Matchers) config.filter_run :focus => true config.filter_run_excluding :external => true # Tests that randomly fail, but may have value. config.filter_run_excluding :volatile => true # Add jruby filters here config.filter_run_excluding :windows_only => true unless windows? config.filter_run_excluding :not_supported_on_win2k3 => true if windows_win2k3? config.filter_run_excluding :not_supported_on_solaris => true if solaris? config.filter_run_excluding :win2k3_only => true unless windows_win2k3? config.filter_run_excluding :windows64_only => true unless windows64? config.filter_run_excluding :windows32_only => true unless windows32? config.filter_run_excluding :system_windows_service_gem_only => true unless system_windows_service_gem? config.filter_run_excluding :unix_only => true unless unix? # Remove this filter once these issues are fixed: OC-9764, OC-9765, OC-9766, OC-9767 config.filter_run_excluding :unsupported_group_provider_platform => true if (os_x? or solaris? or freebsd? or suse?) config.filter_run_excluding :supports_cloexec => true unless supports_cloexec? config.filter_run_excluding :selinux_only => true unless selinux_enabled? config.filter_run_excluding :ruby_18_only => true unless ruby_18? config.filter_run_excluding :ruby_19_only => true unless ruby_19? config.filter_run_excluding :ruby_gte_19_only => true unless ruby_gte_19? config.filter_run_excluding :ruby_20_only => true unless ruby_20? config.filter_run_excluding :ruby_gte_20_only => true unless ruby_gte_20? config.filter_run_excluding :requires_root => true unless ENV['USER'] == 'root' || ENV['LOGIN'] == 'root' config.filter_run_excluding :requires_root_or_running_windows => true unless (ENV['USER'] == 'root' or windows?) config.filter_run_excluding :requires_unprivileged_user => true if ENV['USER'] == 'root' config.filter_run_excluding :uses_diff => true unless has_diff? running_platform_arch = `uname -m`.strip config.filter_run_excluding :arch => lambda {|target_arch| running_platform_arch != target_arch } # Functional Resource tests that are provider-specific: # context "on platforms that use useradd", :provider => {:user => Chef::Provider::User::Useradd}} do #... config.filter_run_excluding :provider => lambda {|criteria| type, target_provider = criteria.first platform = TEST_PLATFORM.dup platform_version = TEST_PLATFORM_VERSION.dup begin provider_for_running_platform = Chef::Platform.find_provider(platform, platform_version, type) provider_for_running_platform != target_provider rescue ArgumentError # no provider for platform true end } config.run_all_when_everything_filtered = true config.treat_symbols_as_metadata_keys_with_true_values = true config.before(:each) do Chef::Config.reset end end require 'webrick/utils' # Webrick uses a centralized/synchronized timeout manager. It works by # starting a thread to check for timeouts on an interval. The timeout # checker thread cannot be stopped or canceled in any easy way, and it # makes calls to Time.new, which fail when rspec is in the process of # creating a method stub for that method. Since our tests don't rely on # any timeout behavior enforced by webrick, disable the timeout manager # via a monkey patch. # # Hopefully this fails loudly if the webrick code should change. As of this # writing, the relevant code is in webrick/utils, which can be located on # your system with: # # $ gem which webrick/utils module WEBrick module Utils class TimeoutHandler def initialize @timeout_info = Hash.new end end end end chef-11.8.2/spec/tiny_server.rb0000644000004100000410000001170212254362222016371 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'rubygems' require 'webrick' require 'webrick/https' require 'rack' #require 'thin' require 'singleton' require 'chef/json_compat' require 'open-uri' require 'chef/config' module TinyServer class Server < Rack::Server attr_writer :app def self.setup(options=nil, &block) tiny_app = new(options) app_code = Rack::Builder.new(&block).to_app tiny_app.app = app_code tiny_app end def shutdown server.shutdown end end class Manager # 5 == debug, 3 == warning LOGGER = WEBrick::Log.new(STDOUT, 3) DEFAULT_OPTIONS = { :server => 'webrick', :Port => 9000, :Host => 'localhost', :environment => :none, :Logger => LOGGER, :AccessLog => [] # Remove this option to enable the access log when debugging. } def initialize(options=nil) @options = options ? DEFAULT_OPTIONS.merge(options) : DEFAULT_OPTIONS @creator = caller.first end def start @server_thread = Thread.new do @server = Server.setup(@options) do run API.instance end @server.start end block_until_started end def url "http://localhost:#{@options[:Port]}" end def block_until_started 200.times do if started? && !@server.nil? return true end end raise "ivar weirdness" if started? && @server.nil? raise "TinyServer failed to boot :/" end def started? open(url) true rescue OpenURI::HTTPError true rescue Errno::ECONNREFUSED, EOFError, Errno::ECONNRESET => e sleep 0.1 # If the host has ":::1 localhost" in its hosts file and if IPv6 # is not enabled we can get NetworkUnreachable exception... rescue Errno::ENETUNREACH => e sleep 0.1 false end def stop # yes, this is terrible. @server.shutdown @server_thread.kill @server_thread.join @server_thread = nil end end class API include Singleton GET = "GET" PUT = "PUT" POST = "POST" DELETE = "DELETE" attr_reader :routes def initialize clear end def clear @routes = {GET => [], PUT => [], POST => [], DELETE => []} end def get(path, response_code, data=nil, headers=nil, &block) @routes[GET] << Route.new(path, Response.new(response_code, data, headers, &block)) end def put(path, response_code, data=nil, headers=nil, &block) @routes[PUT] << Route.new(path, Response.new(response_code, data, headers, &block)) end def post(path, response_code, data=nil, headers=nil, &block) @routes[POST] << Route.new(path, Response.new(response_code, data, headers, &block)) end def delete(path, response_code, data=nil, headers=nil, &block) @routes[DELETE] << Route.new(path, Response.new(response_code, data, headers, &block)) end def call(env) if response = response_for_request(env) response.call else debug_info = {:message => "no data matches the request for #{env['REQUEST_URI']}", :available_routes => @routes, :request => env} # Uncomment me for glorious debugging # pp :not_found => debug_info [404, {'Content-Type' => 'application/json'}, debug_info.to_json] end end def response_for_request(env) if route = @routes[env["REQUEST_METHOD"]].find { |route| route.matches_request?(env["REQUEST_URI"]) } route.response end end end class Route attr_reader :response def initialize(path_spec, response) @path_spec, @response = path_spec, response end def matches_request?(uri) uri = URI.parse(uri).request_uri @path_spec === uri end def to_s "#{@path_spec} => (#{@response})" end end class Response HEADERS = {'Content-Type' => 'application/json'} def initialize(response_code=200, data=nil, headers=nil, &block) @response_code, @data = response_code, data @response_headers = headers ? HEADERS.merge(headers) : HEADERS @block = block_given? ? block : nil end def call data = @data || @block.call [@response_code, @response_headers, Array(data)] end def to_s "#{@response_code} => #{(@data|| @block)}" end end end chef-11.8.2/spec/stress/0000755000004100000410000000000012254362222015015 5ustar www-datawww-datachef-11.8.2/spec/stress/win32/0000755000004100000410000000000012254362222015757 5ustar www-datawww-datachef-11.8.2/spec/stress/win32/memory_spec.rb0000644000004100000410000000141412254362222020626 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe 'Chef::ReservedNames::Win32::Memory', :windows_only do end chef-11.8.2/spec/stress/win32/security_spec.rb0000644000004100000410000000454012254362222021170 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' if windows? require 'chef/win32/security' require 'tmpdir' require 'fileutils' end describe 'Chef::ReservedNames::Win32::Security', :windows_only do def monkeyfoo File.join(CHEF_SPEC_DATA, "monkeyfoo").gsub("/", "\\") end before :all do @test_tempdir = File.join(Dir::tmpdir, "cheftests", "chef_win32_security") FileUtils.mkdir_p(@test_tempdir) @monkeyfoo = File.join(@test_tempdir, "monkeyfoo.txt") end before :each do File.delete(@monkeyfoo) if File.exist?(@monkeyfoo) # Make a file. File.open(@monkeyfoo, "w") do |file| file.write("hi") end end after :all do FileUtils.rm_rf(@test_tempdir) end it "should not leak when retrieving and reading the ACE from a file", :volatile do lambda { sids = Chef::ReservedNames::Win32::Security::SecurableObject.new(@monkeyfoo).security_descriptor.dacl.select { |ace| ace.sid } GC.start }.should_not leak_memory(:warmup => 50, :iterations => 100) end it "should not leak when creating a new ACL and setting it on a file", :volatile do securable_object = Security::SecurableObject.new(@monkeyfoo) lambda { securable_object.dacl = Chef::ReservedNames::Win32::Security::ACL.create([ Chef::ReservedNames::Win32::Security::ACE.access_allowed(Chef::ReservedNames::Win32::Security::SID.Everyone, Chef::ReservedNames::Win32::API::Security::GENERIC_READ), Chef::ReservedNames::Win32::Security::ACE.access_denied(Chef::ReservedNames::Win32::Security::SID.from_account("Users"), Chef::ReservedNames::Win32::API::Security::GENERIC_ALL) ]) GC.start }.should_not leak_memory(:warmup => 50, :iterations => 100) end end chef-11.8.2/spec/stress/win32/file_spec.rb0000644000004100000410000000244412254362222020241 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/win32/file' if windows? describe 'Chef::ReservedNames::Win32::File', :windows_only do before(:each) do @path = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "data", "old_home_dir", "my-dot-emacs")) end it "should not leak memory" do test = lambda { Chef::ReservedNames::Win32::File.symlink?(@path) } test.should_not leak_memory(:warmup => 50, :iterations => 100) end it "should not leak handles" do test = lambda { Chef::ReservedNames::Win32::File.symlink?(@path) } test.should_not leak_handles(:warmup => 50, :iterations => 100) end end chef-11.8.2/spec/integration/0000755000004100000410000000000012254362222016015 5ustar www-datawww-datachef-11.8.2/spec/integration/client/0000755000004100000410000000000012254362222017273 5ustar www-datawww-datachef-11.8.2/spec/integration/client/client_spec.rb0000644000004100000410000001443512254362222022117 0ustar www-datawww-datarequire 'support/shared/integration/integration_helper' require 'chef/mixin/shell_out' describe "chef-client" do extend IntegrationSupport include Chef::Mixin::ShellOut when_the_repository "has a cookbook with a no-op recipe" do file 'cookbooks/x/recipes/default.rb', '' it "should complete with success" do file 'config/client.rb', < chef_dir) result.error! end context 'and no config file' do it 'should complete with success when cwd is just above cookbooks and paths are not specified' do chef_dir = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "bin")) result = shell_out("#{chef_dir}/chef-client -z -o 'x::default' --config-file-jail \"#{path_to('')}\"", :cwd => path_to('')) result.error! end it 'should complete with success when cwd is below cookbooks and paths are not specified' do chef_dir = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "bin")) result = shell_out("#{chef_dir}/chef-client -z -o 'x::default' --config-file-jail \"#{path_to('')}\"", :cwd => path_to('cookbooks/x')) result.error! end it 'should fail when cwd is below high above and paths are not specified' do chef_dir = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "bin")) result = shell_out("#{chef_dir}/chef-client -z -o 'x::default' --config-file-jail \"#{path_to('')}\"", :cwd => File.expand_path('..', path_to(''))) result.exitstatus.should == 1 end end context 'and a config file under .chef/knife.rb' do file '.chef/knife.rb', 'xxx.xxx' it 'should load .chef/knife.rb when -z is specified' do chef_dir = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "bin")) result = shell_out("#{chef_dir}/chef-client -z -o 'x::default' --config-file-jail \"#{path_to('')}\"", :cwd => path_to('')) result.exitstatus.should == 2 end it 'fails to load .chef/knife.rb when -z is specified and --config-file-jail does not include the .chef/knife.rb' do chef_dir = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "bin")) result = shell_out("#{chef_dir}/chef-client -z -o 'x::default' --config-file-jail \"#{path_to('roles')}\"", :cwd => path_to('')) result.error! end end it "should complete with success" do file 'config/client.rb', < chef_dir) result.error! end context 'and a private key' do file 'mykey.pem', < chef_dir) result.error! end end it "should complete with success when passed the -z flag" do file 'config/client.rb', < chef_dir) result.error! end it "should complete with success when passed the --local-mode flag" do file 'config/client.rb', < chef_dir) result.error! end it "should complete with success when passed -z and --chef-zero-port" do file 'config/client.rb', < chef_dir) result.error! end end end chef-11.8.2/spec/integration/knife/0000755000004100000410000000000012254362222017111 5ustar www-datawww-datachef-11.8.2/spec/integration/knife/common_options_spec.rb0000644000004100000410000000774012254362222023523 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'support/shared/integration/integration_helper' require 'chef/knife/raw' describe 'knife common options' do extend IntegrationSupport include KnifeSupport when_the_repository "has a node" do file 'nodes/x.json', {} before(:each) do if ChefZero::RSpec.server ChefZero::RSpec.server.stop ChefZero::RSpec.server = nil end end context 'When chef_zero.enabled is true' do before(:each) do Chef::Config.chef_zero.enabled = true end it 'knife raw /nodes/x should retrieve the role' do knife('raw /nodes/x').should_succeed /"name": "x"/ end context 'And chef_zero.port is 9999' do before(:each) { Chef::Config.chef_zero.port = 9999 } it 'knife raw /nodes/x should retrieve the role' do knife('raw /nodes/x').should_succeed /"name": "x"/ Chef::Config.chef_server_url.should == 'http://127.0.0.1:9999' end end context 'and there is a private key' do file 'mykey.pem', <) # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'support/shared/integration/integration_helper' require 'chef/knife/list' require 'chef/knife/delete' require 'chef/knife/show' require 'chef/knife/raw' require 'chef/knife/cookbook_upload' describe 'knife raw -z' do extend IntegrationSupport include KnifeSupport when_the_repository "has one of each thing" do file 'clients/x.json', {} file 'cookbooks/x/metadata.rb', 'version "1.0.0"' file 'data_bags/x/y.json', {} file 'environments/x.json', {} file 'nodes/x.json', {} file 'roles/x.json', {} file 'users/x.json', {} context 'GET /TYPE' do it 'knife list -z -R returns everything' do knife('list -z -Rfp /').should_succeed < (RUBY_VERSION < "1.9") do knife("raw -z -i #{path_to('rolestuff.json')} -m PUT /roles/x").should_succeed /"x"/ IO.read(path_to('roles/x.json')).should == < 'z' } file 'empty_id.json', { 'id' => 'z' } file 'rolestuff.json', '{"description":"hi there","name":"x"}' file 'cookbooks_to_upload/z/metadata.rb', "version '1.0.0'" it 'knife raw -z -i empty.json -m POST /clients' do knife("raw -z -i #{path_to('empty.json')} -m POST /clients").should_succeed /uri/ knife('list --local /clients').should_succeed "/clients/z.json\n" end it 'knife cookbook upload works' do knife("cookbook upload -z --cookbook-path #{path_to('cookbooks_to_upload')} z").should_succeed < (RUBY_VERSION < "1.9") do knife("raw -z -i #{path_to('rolestuff.json')} -m POST /roles").should_succeed /uri/ IO.read(path_to('roles/x.json')).should == <) # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'support/shared/integration/integration_helper' require 'chef/knife/deps' describe 'knife deps' do extend IntegrationSupport include KnifeSupport context 'local' do when_the_repository 'has a role with no run_list' do file 'roles/starring.json', {} it 'knife deps reports no dependencies' do knife('deps /roles/starring.json').should_succeed "/roles/starring.json\n" end end when_the_repository 'has a role with a default run_list' do file 'roles/starring.json', { 'run_list' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) } file 'roles/minor.json', {} file 'cookbooks/quiche/metadata.rb', 'name "quiche"' file 'cookbooks/quiche/recipes/default.rb', '' file 'cookbooks/soup/metadata.rb', 'name "soup"' file 'cookbooks/soup/recipes/chicken.rb', '' it 'knife deps reports all dependencies' do knife('deps /roles/starring.json').should_succeed < { 'desert' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) } } file 'roles/minor.json', {} file 'cookbooks/quiche/metadata.rb', 'name "quiche"' file 'cookbooks/quiche/recipes/default.rb', '' file 'cookbooks/soup/metadata.rb', 'name "soup"' file 'cookbooks/soup/recipes/chicken.rb', '' it 'knife deps reports all dependencies' do knife('deps /roles/starring.json').should_succeed < 'desert' } it 'knife deps reports just the node' do knife('deps /nodes/mort.json').should_succeed "/environments/desert.json\n/nodes/mort.json\n" end end when_the_repository 'has a node with roles and recipes in its run_list' do file 'roles/minor.json', {} file 'cookbooks/quiche/metadata.rb', 'name "quiche"' file 'cookbooks/quiche/recipes/default.rb', '' file 'cookbooks/soup/metadata.rb', 'name "soup"' file 'cookbooks/soup/recipes/chicken.rb', '' file 'nodes/mort.json', { 'run_list' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) } it 'knife deps reports just the node' do knife('deps /nodes/mort.json').should_succeed < %w(role[minor] recipe[quiche] recipe[soup::chicken]) } file 'roles/minor.json', {} file 'cookbooks/quiche/metadata.rb', 'name "quiche"' file 'cookbooks/quiche/recipes/default.rb', '' file 'cookbooks/soup/metadata.rb', 'name "soup"' file 'cookbooks/soup/recipes/chicken.rb', '' file 'environments/desert.json', {} file 'nodes/mort.json', { 'chef_environment' => 'desert', 'run_list' => [ 'role[starring]' ] } file 'nodes/bart.json', { 'run_list' => [ 'role[minor]' ] } it 'knife deps reports all dependencies' do knife('deps /nodes/mort.json').should_succeed < [ 'role[bar]' ] } file 'roles/bar.json', { 'run_list' => [ 'role[baz]' ] } file 'roles/baz.json', { 'run_list' => [ 'role[foo]' ] } file 'roles/self.json', { 'run_list' => [ 'role[self]' ] } it 'knife deps prints each once' do knife('deps /roles/foo.json /roles/self.json').should_succeed < 2, :stdout => "/blah\n", :stderr => "ERROR: /blah: No such file or directory\n" ) end it 'knife deps /roles/x.json reports an error' do knife('deps /roles/x.json').should_fail( :exit_code => 2, :stdout => "/roles/x.json\n", :stderr => "ERROR: /roles/x.json: No such file or directory\n" ) end it 'knife deps /nodes/x.json reports an error' do knife('deps /nodes/x.json').should_fail( :exit_code => 2, :stdout => "/nodes/x.json\n", :stderr => "ERROR: /nodes/x.json: No such file or directory\n" ) end it 'knife deps /environments/x.json reports an error' do knife('deps /environments/x.json').should_fail( :exit_code => 2, :stdout => "/environments/x.json\n", :stderr => "ERROR: /environments/x.json: No such file or directory\n" ) end it 'knife deps /cookbooks/x reports an error' do knife('deps /cookbooks/x').should_fail( :exit_code => 2, :stdout => "/cookbooks/x\n", :stderr => "ERROR: /cookbooks/x: No such file or directory\n" ) end it 'knife deps /data_bags/bag/item reports an error' do knife('deps /data_bags/bag/item').should_fail( :exit_code => 2, :stdout => "/data_bags/bag/item\n", :stderr => "ERROR: /data_bags/bag/item: No such file or directory\n" ) end end when_the_repository 'is missing a dependent cookbook' do file 'roles/starring.json', { 'run_list' => [ 'recipe[quiche]'] } it 'knife deps reports the cookbook, along with an error' do knife('deps /roles/starring.json').should_fail( :exit_code => 2, :stdout => "/cookbooks/quiche\n/roles/starring.json\n", :stderr => "ERROR: /cookbooks/quiche: No such file or directory\n" ) end end when_the_repository 'is missing a dependent environment' do file 'nodes/mort.json', { 'chef_environment' => 'desert' } it 'knife deps reports the environment, along with an error' do knife('deps /nodes/mort.json').should_fail( :exit_code => 2, :stdout => "/environments/desert.json\n/nodes/mort.json\n", :stderr => "ERROR: /environments/desert.json: No such file or directory\n" ) end end when_the_repository 'is missing a dependent role' do file 'roles/starring.json', { 'run_list' => [ 'role[minor]'] } it 'knife deps reports the role, along with an error' do knife('deps /roles/starring.json').should_fail( :exit_code => 2, :stdout => "/roles/minor.json\n/roles/starring.json\n", :stderr => "ERROR: /roles/minor.json: No such file or directory\n" ) end end end context 'invalid objects' do when_the_repository 'is empty' do it 'knife deps / reports itself only' do knife('deps /').should_succeed("/\n") end it 'knife deps /roles reports an error' do knife('deps /roles').should_fail( :exit_code => 2, :stderr => "ERROR: /roles: No such file or directory\n", :stdout => "/roles\n" ) end end when_the_repository 'has a data bag' do file 'data_bags/bag/item.json', '' it 'knife deps /data_bags/bag shows no dependencies' do knife('deps /data_bags/bag').should_succeed("/data_bags/bag\n") end end when_the_repository 'has a cookbook' do file 'cookbooks/blah/metadata.rb', 'name "blah"' it 'knife deps on a cookbook file shows no dependencies' do knife('deps /cookbooks/blah/metadata.rb').should_succeed( "/cookbooks/blah/metadata.rb\n" ) end end end end context 'remote' do when_the_chef_server 'has a role with no run_list' do role 'starring', {} it 'knife deps reports no dependencies' do knife('deps --remote /roles/starring.json').should_succeed "/roles/starring.json\n" end end when_the_chef_server 'has a role with a default run_list' do role 'starring', { 'run_list' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) } role 'minor', {} cookbook 'quiche', '1.0.0', { 'metadata.rb' => "name 'quiche'\nversion '1.0.0'\n", 'recipes' => { 'default.rb' => '' } } cookbook 'soup', '1.0.0', { 'metadata.rb' => "name 'soup'\nversion '1.0.0'\n", 'recipes' => { 'chicken.rb' => '' } } it 'knife deps reports all dependencies' do knife('deps --remote /roles/starring.json').should_succeed < { 'desert' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) } } role 'minor', {} cookbook 'quiche', '1.0.0', { 'metadata.rb' => "name 'quiche'\nversion '1.0.0'\n", 'recipes' => { 'default.rb' => '' } } cookbook 'soup', '1.0.0', { 'metadata.rb' => "name 'soup'\nversion '1.0.0'\n", 'recipes' => { 'chicken.rb' => '' } } it 'knife deps reports all dependencies' do knife('deps --remote /roles/starring.json').should_succeed < 'desert' } it 'knife deps reports just the node' do knife('deps --remote /nodes/mort.json').should_succeed "/environments/desert.json\n/nodes/mort.json\n" end end when_the_chef_server 'has a node with roles and recipes in its run_list' do role 'minor', {} cookbook 'quiche', '1.0.0', { 'metadata.rb' => "name 'quiche'\nversion '1.0.0'\n", 'recipes' => { 'default.rb' => '' } } cookbook 'soup', '1.0.0', { 'metadata.rb' => "name 'soup'\nversion '1.0.0'\n", 'recipes' => { 'chicken.rb' => '' } } node 'mort', { 'run_list' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) } it 'knife deps reports just the node' do knife('deps --remote /nodes/mort.json').should_succeed < "name 'quiche'\nversion '1.0.0'\n", 'recipes' => { 'default.rb' => '' } } it 'knife deps reports just the cookbook' do knife('deps --remote /cookbooks/quiche').should_succeed "/cookbooks/quiche\n" end end when_the_chef_server 'has a cookbook with dependencies' do cookbook 'kettle', '1.0.0', { 'metadata.rb' => "name 'kettle'\nversion '1.0.0'\n" } cookbook 'quiche', '1.0.0', { 'metadata.rb' => "name 'quiche'\ndepends 'kettle'\n", 'recipes' => { 'default.rb' => '' } } it 'knife deps reports the cookbook and its dependencies' do knife('deps --remote /cookbooks/quiche').should_succeed "/cookbooks/kettle\n/cookbooks/quiche\n" end end when_the_chef_server 'has a data bag' do data_bag 'bag', { 'item' => {} } it 'knife deps reports just the data bag' do knife('deps --remote /data_bags/bag/item.json').should_succeed "/data_bags/bag/item.json\n" end end when_the_chef_server 'has an environment' do environment 'desert', {} it 'knife deps reports just the environment' do knife('deps --remote /environments/desert.json').should_succeed "/environments/desert.json\n" end end when_the_chef_server 'has a deep dependency tree' do role 'starring', { 'run_list' => %w(role[minor] recipe[quiche] recipe[soup::chicken]) } role 'minor', {} cookbook 'quiche', '1.0.0', { 'metadata.rb' => "name 'quiche'\nversion '1.0.0'\n", 'recipes' => { 'default.rb' => '' } } cookbook 'soup', '1.0.0', { 'metadata.rb' => "name 'soup'\nversion '1.0.0'\n", 'recipes' => { 'chicken.rb' => '' } } environment 'desert', {} node 'mort', { 'chef_environment' => 'desert', 'run_list' => [ 'role[starring]' ] } node 'bart', { 'run_list' => [ 'role[minor]' ] } it 'knife deps reports all dependencies' do knife('deps --remote /nodes/mort.json').should_succeed < "name 'foo'\ndepends 'bar'\n" } cookbook 'bar', '1.0.0', { 'metadata.rb' => "name 'bar'\ndepends 'baz'\n" } cookbook 'baz', '1.0.0', { 'metadata.rb' => "name 'baz'\ndepends 'foo'\n" } cookbook 'self', '1.0.0', { 'metadata.rb' => "name 'self'\ndepends 'self'\n" } it 'knife deps prints each once' do knife('deps --remote /cookbooks/foo /cookbooks/self').should_succeed < [ 'role[bar]' ] } role 'bar', { 'run_list' => [ 'role[baz]' ] } role 'baz', { 'run_list' => [ 'role[foo]' ] } role 'self', { 'run_list' => [ 'role[self]' ] } it 'knife deps prints each once' do knife('deps --remote /roles/foo.json /roles/self.json').should_succeed < 2, :stdout => "/blah\n", :stderr => "ERROR: /blah: No such file or directory\n" ) end it 'knife deps /roles/x.json reports an error' do knife('deps --remote /roles/x.json').should_fail( :exit_code => 2, :stdout => "/roles/x.json\n", :stderr => "ERROR: /roles/x.json: No such file or directory\n" ) end it 'knife deps /nodes/x.json reports an error' do knife('deps --remote /nodes/x.json').should_fail( :exit_code => 2, :stdout => "/nodes/x.json\n", :stderr => "ERROR: /nodes/x.json: No such file or directory\n" ) end it 'knife deps /environments/x.json reports an error' do knife('deps --remote /environments/x.json').should_fail( :exit_code => 2, :stdout => "/environments/x.json\n", :stderr => "ERROR: /environments/x.json: No such file or directory\n" ) end it 'knife deps /cookbooks/x reports an error' do knife('deps --remote /cookbooks/x').should_fail( :exit_code => 2, :stdout => "/cookbooks/x\n", :stderr => "ERROR: /cookbooks/x: No such file or directory\n" ) end it 'knife deps /data_bags/bag/item reports an error' do knife('deps --remote /data_bags/bag/item').should_fail( :exit_code => 2, :stdout => "/data_bags/bag/item\n", :stderr => "ERROR: /data_bags/bag/item: No such file or directory\n" ) end end when_the_chef_server 'is missing a dependent cookbook' do role 'starring', { 'run_list' => [ 'recipe[quiche]'] } it 'knife deps reports the cookbook, along with an error' do knife('deps --remote /roles/starring.json').should_fail( :exit_code => 2, :stdout => "/cookbooks/quiche\n/roles/starring.json\n", :stderr => "ERROR: /cookbooks/quiche: No such file or directory\n" ) end end when_the_chef_server 'is missing a dependent environment' do node 'mort', { 'chef_environment' => 'desert' } it 'knife deps reports the environment, along with an error' do knife('deps --remote /nodes/mort.json').should_fail( :exit_code => 2, :stdout => "/environments/desert.json\n/nodes/mort.json\n", :stderr => "ERROR: /environments/desert.json: No such file or directory\n" ) end end when_the_chef_server 'is missing a dependent role' do role 'starring', { 'run_list' => [ 'role[minor]'] } it 'knife deps reports the role, along with an error' do knife('deps --remote /roles/starring.json').should_fail( :exit_code => 2, :stdout => "/roles/minor.json\n/roles/starring.json\n", :stderr => "ERROR: /roles/minor.json: No such file or directory\n" ) end end end context 'invalid objects' do when_the_chef_server 'is empty' do it 'knife deps / reports an error' do knife('deps --remote /').should_succeed("/\n") end it 'knife deps /roles reports an error' do knife('deps --remote /roles').should_succeed("/roles\n") end end when_the_chef_server 'has a data bag' do data_bag 'bag', { 'item' => {} } it 'knife deps /data_bags/bag shows no dependencies' do knife('deps --remote /data_bags/bag').should_succeed("/data_bags/bag\n") end end when_the_chef_server 'has a cookbook' do cookbook 'blah', '1.0.0', { 'metadata.rb' => 'name "blah"' } it 'knife deps on a cookbook file shows no dependencies' do knife('deps --remote /cookbooks/blah/metadata.rb').should_succeed( "/cookbooks/blah/metadata.rb\n" ) end end end end it 'knife deps --no-recurse reports an error' do knife('deps --no-recurse /').should_fail("ERROR: --no-recurse requires --tree\n") end end chef-11.8.2/spec/integration/knife/diff_spec.rb0000644000004100000410000004332412254362222021366 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'support/shared/integration/integration_helper' require 'chef/knife/diff' describe 'knife diff' do extend IntegrationSupport include KnifeSupport context 'without versioned cookbooks' do when_the_chef_server "has one of each thing" do client 'x', '{}' cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"' } data_bag 'x', { 'y' => '{}' } environment 'x', '{}' node 'x', '{}' role 'x', '{}' user 'x', '{}' when_the_repository 'has only top-level directories' do directory 'clients' directory 'cookbooks' directory 'data_bags' directory 'environments' directory 'nodes' directory 'roles' directory 'users' it 'knife diff reports everything as deleted' do knife('diff --name-status /').should_succeed < true, 'public_key' => ChefZero::PUBLIC_KEY } file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY } file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY } file 'cookbooks/x/metadata.rb', 'version "1.0.0"' file 'data_bags/x/y.json', {} file 'environments/_default.json', { "description" => "The default Chef environment" } file 'environments/x.json', {} file 'nodes/x.json', {} file 'roles/x.json', {} file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY } file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY } it 'knife diff reports no differences' do knife('diff /').should_succeed '' end it 'knife diff /environments/nonexistent.json reports an error' do knife('diff /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory on remote or local\n" end it 'knife diff /environments/*.txt reports an error' do knife('diff /environments/*.txt').should_fail "ERROR: /environments/*.txt: No such file or directory on remote or local\n" end context 'except the role file' do file 'roles/x.json', < ChefZero::PUBLIC_KEY } file 'cookbooks/x/blah.rb', '' file 'cookbooks/y/metadata.rb', 'version "1.0.0"' file 'data_bags/x/z.json', {} file 'data_bags/y/zz.json', {} file 'environments/y.json', {} file 'nodes/y.json', {} file 'roles/y.json', {} file 'users/y.json', { 'public_key' => ChefZero::PUBLIC_KEY } it 'knife diff reports the new files as added' do knife('diff --name-status /').should_succeed < 'version "1.0.0"', 'onlyin1.0.0.rb' => ''} cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => '' } it 'knife diff /cookbooks/x shows differences' do knife('diff --name-status /cookbooks/x').should_succeed < 'version "1.0.0"', 'onlyin1.0.0.rb' => '' } cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => '' } it 'knife diff /cookbooks/x shows no differences' do knife('diff --name-status /cookbooks/x').should_succeed '' end end when_the_chef_server 'has a later version for the cookbook, and no current version' do cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => '' } it 'knife diff /cookbooks/x shows the differences' do knife('diff --name-status /cookbooks/x').should_succeed < 'version "0.9.9"', 'onlyin0.9.9.rb' => '' } it 'knife diff /cookbooks/x shows the differences' do knife('diff --name-status /cookbooks/x').should_succeed < 'hi' } it 'knife diff reports the difference', :pending => (RUBY_VERSION < "1.9") do knife('diff /environments/x.json').should_succeed(/ { - "name": "x", - "description": "hi" \+ "name": "x" } /) end end end when_the_repository 'has an environment file with a value in it' do file 'environments/x.json', { 'description' => 'hi' } when_the_chef_server 'has an environment with the same value' do environment 'x', { 'description' => 'hi' } it 'knife diff returns no differences' do knife('diff /environments/x.json').should_succeed '' end end when_the_chef_server 'has an environment with no value' do environment 'x', {} it 'knife diff reports the difference', :pending => (RUBY_VERSION < "1.9") do knife('diff /environments/x.json').should_succeed(/ { - "name": "x" \+ "name": "x", \+ "description": "hi" } /) end end when_the_chef_server 'has an environment with a different value' do environment 'x', { 'description' => 'lo' } it 'knife diff reports the difference', :pending => (RUBY_VERSION < "1.9") do knife('diff /environments/x.json').should_succeed(/ { "name": "x", - "description": "lo" \+ "description": "hi" } /) end end end end when_the_chef_server 'has an environment' do environment 'x', {} when_the_repository 'has an environment with bad JSON' do file 'environments/x.json', '{' it 'knife diff reports an error and does a textual diff' do knife('diff /environments/x.json').should_succeed(/- "name": "x"/, :stderr => "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: A JSON text must at least contain two octets!\n") end end end end # without versioned cookbooks with_versioned_cookbooks do when_the_chef_server "has one of each thing" do client 'x', '{}' cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"' } data_bag 'x', { 'y' => '{}' } environment 'x', '{}' node 'x', '{}' role 'x', '{}' user 'x', '{}' when_the_repository 'has only top-level directories' do directory 'clients' directory 'cookbooks' directory 'data_bags' directory 'environments' directory 'nodes' directory 'roles' directory 'users' it 'knife diff reports everything as deleted' do knife('diff --name-status /').should_succeed < true, 'public_key' => ChefZero::PUBLIC_KEY } file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY } file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY } file 'cookbooks/x-1.0.0/metadata.rb', 'version "1.0.0"' file 'data_bags/x/y.json', {} file 'environments/_default.json', { "description" => "The default Chef environment" } file 'environments/x.json', {} file 'nodes/x.json', {} file 'roles/x.json', {} file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY } file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY } it 'knife diff reports no differences' do knife('diff /').should_succeed '' end it 'knife diff /environments/nonexistent.json reports an error' do knife('diff /environments/nonexistent.json').should_fail "ERROR: /environments/nonexistent.json: No such file or directory on remote or local\n" end it 'knife diff /environments/*.txt reports an error' do knife('diff /environments/*.txt').should_fail "ERROR: /environments/*.txt: No such file or directory on remote or local\n" end context 'except the role file' do file 'roles/x.json', < 'version "1.0.0"', 'onlyin1.0.0.rb' => ''} cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => '' } it 'knife diff /cookbooks shows differences' do knife('diff --name-status /cookbooks').should_succeed < 'version "1.0.0"', 'onlyin1.0.0.rb' => '' } cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => '' } it 'knife diff /cookbooks shows the differences' do knife('diff --name-status /cookbooks').should_succeed "D\t/cookbooks/x-0.9.9\n" end end when_the_chef_server 'has a later version for the cookbook, and no current version' do cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => '' } it 'knife diff /cookbooks shows the differences' do knife('diff --name-status /cookbooks').should_succeed < 'version "0.9.9"', 'onlyin0.9.9.rb' => '' } it 'knife diff /cookbooks shows the differences' do knife('diff --name-status /cookbooks').should_succeed < 'hi' } it 'knife diff reports the difference', :pending => (RUBY_VERSION < "1.9") do knife('diff /environments/x.json').should_succeed(/ { - "name": "x", - "description": "hi" \+ "name": "x" } /) end end end when_the_repository 'has an environment file with a value in it' do file 'environments/x.json', { 'description' => 'hi' } when_the_chef_server 'has an environment with the same value' do environment 'x', { 'description' => 'hi' } it 'knife diff returns no differences' do knife('diff /environments/x.json').should_succeed '' end end when_the_chef_server 'has an environment with no value' do environment 'x', {} it 'knife diff reports the difference', :pending => (RUBY_VERSION < "1.9") do knife('diff /environments/x.json').should_succeed(/ { - "name": "x" \+ "name": "x", \+ "description": "hi" } /) end end when_the_chef_server 'has an environment with a different value' do environment 'x', { 'description' => 'lo' } it 'knife diff reports the difference', :pending => (RUBY_VERSION < "1.9") do knife('diff /environments/x.json').should_succeed(/ { "name": "x", - "description": "lo" \+ "description": "hi" } /) end end end end when_the_chef_server 'has an environment' do environment 'x', {} when_the_repository 'has an environment with bad JSON' do file 'environments/x.json', '{' it 'knife diff reports an error and does a textual diff' do knife('diff /environments/x.json').should_succeed(/- "name": "x"/, :stderr => "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: A JSON text must at least contain two octets!\n") end end end end # without versioned cookbooks end chef-11.8.2/spec/integration/knife/chef_repo_path_spec.rb0000644000004100000410000006135112254362222023424 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'support/shared/integration/integration_helper' require 'chef/knife/list' require 'chef/knife/show' describe 'chef_repo_path tests' do extend IntegrationSupport include KnifeSupport # TODO alternate repo_path / *_path context 'alternate *_path' do when_the_repository 'has clients and clients2, cookbooks and cookbooks2, etc.' do file 'clients/client1.json', {} file 'cookbooks/cookbook1/metadata.rb', '' file 'data_bags/bag/item.json', {} file 'environments/env1.json', {} file 'nodes/node1.json', {} file 'roles/role1.json', {} file 'users/user1.json', {} file 'clients2/client2.json', {} file 'cookbooks2/cookbook2/metadata.rb', '' file 'data_bags2/bag2/item2.json', {} file 'environments2/env2.json', {} file 'nodes2/node2.json', {} file 'roles2/role2.json', {} file 'users2/user2.json', {} directory 'chef_repo2' do file 'clients/client3.json', {} file 'cookbooks/cookbook3/metadata.rb', '' file 'data_bags/bag3/item3.json', {} file 'environments/env3.json', {} file 'nodes/node3.json', {} file 'roles/role3.json', {} file 'users/user3.json', {} end it 'knife list --local -Rfp --chef-repo-path chef_repo2 / grabs chef_repo2 stuff' do Chef::Config.delete(:chef_repo_path) knife("list --local -Rfp --chef-repo-path #{path_to('chef_repo2')} /").should_succeed < "WARN: Cookbook 'blah' is empty or entirely chefignored at #{Chef::Config.cookbook_path[0]}/blah\n") /cookbooks/blah/ /cookbooks/blah/metadata.rb /cookbooks/cookbook1/ /cookbooks/cookbook1/metadata.rb /cookbooks/cookbook2/ /cookbooks/cookbook2/metadata.rb EOM end end context 'when there is a cookbook in cookbooks1 and a cookbook in cookbooks2 with the same name' do file 'cookbooks/blah/metadata.json', {} file 'cookbooks2/blah/metadata.rb', '' it 'knife list -Rfp cookbooks shows files in the first cookbook and not the second' do knife('list --local -Rfp /cookbooks').should_succeed(< "WARN: Child with name 'blah' found in multiple directories: #{Chef::Config.cookbook_path[0]}/blah and #{Chef::Config.cookbook_path[1]}/blah\n") /cookbooks/blah/ /cookbooks/blah/metadata.json /cookbooks/cookbook1/ /cookbooks/cookbook1/metadata.rb /cookbooks/cookbook2/ /cookbooks/cookbook2/metadata.rb EOM end end context 'when there is a file in data_bags1 and a directory in data_bags2 with the same name' do file 'data_bags/blah', '' file 'data_bags2/blah/item.json', '' it 'knife list -Rfp data_bags shows files in blah' do knife('list --local -Rfp /data_bags').should_succeed < "WARN: Child with name 'blah' found in multiple directories: #{Chef::Config.data_bag_path[0]}/blah and #{Chef::Config.data_bag_path[1]}/blah\n") /data_bags/bag/ /data_bags/bag/item.json /data_bags/bag2/ /data_bags/bag2/item2.json /data_bags/blah/ /data_bags/blah/item1.json EOM end end context 'when there is a directory in environments1 and file in environments2 with the same name' do directory 'environments/blah.json' file 'environments2/blah.json', {} it 'knife show /environments/blah.json succeeds' do knife('show --local /environments/blah.json').should_succeed <) # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'support/shared/integration/integration_helper' require 'chef/knife/list' describe 'knife list' do extend IntegrationSupport include KnifeSupport when_the_chef_server "is empty" do it "knife list / returns all top level directories" do knife('list /').should_succeed < '' } cookbook 'cookbook2', '1.0.1', { 'metadata.rb' => '', 'recipes' => { 'default.rb' => '' } } data_bag 'bag1', { 'item1' => {}, 'item2' => {} } data_bag 'bag2', { 'item1' => {}, 'item2' => {} } environment 'environment1', {} environment 'environment2', {} node 'node1', {} node 'node2', {} role 'role1', {} role 'role2', {} user 'user1', {} user 'user2', {} it "knife list / returns all top level directories" do knife('list /').should_succeed < (Chef::Platform.windows?) do directory 'cookbooks' symlink 'symlinked', 'cookbooks' context 'when cwd is in cookbooks/' do cwd 'cookbooks' it "knife list -Rfp returns cookbooks" do knife('list -Rfp').should_succeed < (Chef::Platform.windows?) do directory 'real_cookbooks' symlink 'cookbooks', 'real_cookbooks' context 'when cwd is in real_cookbooks/' do cwd 'real_cookbooks' it "knife list -Rfp returns cookbooks" do knife('list -Rfp').should_succeed <) # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'support/shared/integration/integration_helper' require 'chef/knife/list' require 'chef/knife/show' describe 'General chef_repo file system checks' do extend IntegrationSupport include KnifeSupport context 'directories and files that should/should not be ignored' do when_the_repository "has empty roles, environments and data bag item directories" do directory "roles" directory "environments" directory "data_bags/bag1" it "knife list --local -Rfp / returns them" do knife('list --local -Rfp /').should_succeed < "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n") /cookbooks/ EOM end end when_the_repository "has only empty cookbook subdirectories" do directory 'cookbooks/cookbook1/recipes' it "knife list --local -Rfp / does not return it" do knife('list --local -Rfp /').should_succeed(< "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n") /cookbooks/ EOM end end when_the_repository "has empty and non-empty cookbook subdirectories" do directory 'cookbooks/cookbook1/recipes' file 'cookbooks/cookbook1/templates/default/x.txt', '' it "knife list --local -Rfp / does not return the empty ones" do knife('list --local -Rfp /').should_succeed < "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n") /cookbooks/ EOM end end when_the_repository "has empty cookbook sub-sub-directories alongside non-empty ones" do file 'cookbooks/cookbook1/templates/default/x.txt', '' directory 'cookbooks/cookbook1/templates/rhel' directory 'cookbooks/cookbook1/files/default' it "knife list --local -Rfp / does not return the empty ones" do knife('list --local -Rfp /').should_succeed <) # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'support/shared/integration/integration_helper' require 'chef/knife/delete' require 'chef/knife/list' require 'chef/knife/raw' describe 'knife delete' do extend IntegrationSupport include KnifeSupport let :everything do < 'version "1.0.0"' } data_bag 'x', { 'y' => '{}' } environment 'x', '{}' node 'x', '{}' role 'x', '{}' user 'x', '{}' when_the_repository 'also has one of each thing' do file 'clients/x.json', {} file 'cookbooks/x/metadata.rb', '' file 'data_bags/x/y.json', {} file 'environments/_default.json', {} file 'environments/x.json', {} file 'nodes/x.json', {} file 'roles/x.json', {} file 'users/x.json', {} it 'knife delete --both /cookbooks/x fails' do knife('delete --both /cookbooks/x').should_fail < "ERROR: /environments/_default.json (remote) cannot be deleted (default environment cannot be modified).\n", :stdout => "Deleted /environments/_default.json\n" knife('list -Rf /').should_succeed server_everything knife('list -Rf --local /').should_succeed < "ERROR: /environments/_default.json (remote) cannot be deleted (default environment cannot be modified).\n" knife('list -Rf /').should_succeed server_everything knife('list -Rf --local /').should_succeed nothing end it 'knife delete --both / fails' do knife('delete --both /').should_fail "ERROR: / (remote) cannot be deleted.\nERROR: / (local) cannot be deleted.\n" knife('list -Rf /').should_succeed server_everything knife('list -Rf --local /').should_succeed nothing end it 'knife delete --both -r /* fails' do knife('delete --both -r /*').should_fail < /USAGE/ knife('list -Rf /').should_succeed < "ERROR: /environments/_default.json (remote) cannot be deleted (default environment cannot be modified).\n", :stdout => "Deleted /environments/_default.json\n" knife('list -Rf /').should_succeed server_nothing knife('list -Rf --local /').should_succeed < /USAGE/ knife('list -Rf /').should_succeed < 'version "1.0.0"', 'onlyin1.0.0.rb' => '' } cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => 'hi' } # TODO this seems wrong it 'knife delete --both -r /cookbooks/x deletes the latest version on the server and the local version' do knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n" knife('raw /cookbooks/x').should_succeed(/1.0.0/) knife('list --local /cookbooks').should_succeed '' end end when_the_chef_server 'has an earlier version for the cookbook' do cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"', 'onlyin1.0.0.rb' => ''} cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => 'hi' } it 'knife delete --both /cookbooks/x deletes the latest version on the server and the local version' do knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n" knife('raw /cookbooks/x').should_succeed(/0.9.9/) knife('list --local /cookbooks').should_succeed '' end end when_the_chef_server 'has a later version for the cookbook, and no current version' do cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => 'hi' } it 'knife delete --both /cookbooks/x deletes the server and client version of the cookbook' do knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n" knife('raw /cookbooks/x').should_fail(/404/) knife('list --local /cookbooks').should_succeed '' end end when_the_chef_server 'has an earlier version for the cookbook, and no current version' do cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => 'hi' } it 'knife delete --both /cookbooks/x deletes the server and client version of the cookbook' do knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n" knife('raw /cookbooks/x').should_fail(/404/) knife('list --local /cookbooks').should_succeed '' end end end when_the_repository 'is empty' do when_the_chef_server 'has two versions of a cookbook' do cookbook 'x', '2.0.11', { 'metadata.rb' => 'version "2.0.11"' } cookbook 'x', '11.0.0', { 'metadata.rb' => 'version "11.0.0"' } it 'knife delete deletes the latest version' do knife('delete --both -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n" knife('raw /cookbooks/x').should_succeed /2.0.11/ end end end end chef-11.8.2/spec/integration/knife/upload_spec.rb0000644000004100000410000012132312254362222021736 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'support/shared/integration/integration_helper' require 'chef/knife/upload' require 'chef/knife/diff' require 'chef/knife/raw' describe 'knife upload' do extend IntegrationSupport include KnifeSupport context 'without versioned cookbooks' do when_the_chef_server "has one of each thing" do client 'x', {} cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"' } data_bag 'x', { 'y' => {} } environment 'x', {} node 'x', {} role 'x', {} user 'x', {} when_the_repository 'has only top-level directories' do directory 'clients' directory 'cookbooks' directory 'data_bags' directory 'environments' directory 'nodes' directory 'roles' directory 'users' it 'knife upload does nothing' do knife('upload /').should_succeed '' knife('diff --name-status /').should_succeed < "WARNING: /environments/_default.json cannot be deleted (default environment cannot be modified).\n") Deleted extra entry /clients/chef-validator.json (purge is on) Deleted extra entry /clients/chef-webui.json (purge is on) Deleted extra entry /clients/x.json (purge is on) Deleted extra entry /cookbooks/x (purge is on) Deleted extra entry /data_bags/x (purge is on) Deleted extra entry /environments/x.json (purge is on) Deleted extra entry /nodes/x.json (purge is on) Deleted extra entry /roles/x.json (purge is on) Deleted extra entry /users/admin.json (purge is on) Deleted extra entry /users/x.json (purge is on) EOM knife('diff --name-status /').should_succeed < true, 'public_key' => ChefZero::PUBLIC_KEY } file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY } file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY } file 'cookbooks/x/metadata.rb', 'version "1.0.0"' file 'data_bags/x/y.json', {} file 'environments/_default.json', { "description" => "The default Chef environment" } file 'environments/x.json', {} file 'nodes/x.json', {} file 'roles/x.json', {} file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY } file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY } it 'knife upload makes no changes' do knife('upload /cookbooks/x').should_succeed '' knife('diff --name-status /').should_succeed '' end it 'knife upload --purge makes no changes' do knife('upload --purge /').should_succeed '' knife('diff --name-status /').should_succeed '' end context 'except the role file' do file 'roles/x.json', { 'description' => 'blarghle' } it 'knife upload changes the role' do knife('upload /').should_succeed "Updated /roles/x.json\n" knife('diff --name-status /').should_succeed '' end it 'knife upload --no-diff does not change the role' do knife('upload --no-diff /').should_succeed '' knife('diff --name-status /').should_succeed "M\t/roles/x.json\n" end end context 'except the role file is textually different, but not ACTUALLY different' do file 'roles/x.json', < ChefZero::PUBLIC_KEY } file 'cookbooks/x/blah.rb', '' file 'cookbooks/y/metadata.rb', 'version "1.0.0"' file 'data_bags/x/z.json', {} file 'data_bags/y/zz.json', {} file 'environments/y.json', {} file 'nodes/y.json', {} file 'roles/y.json', {} file 'users/y.json', { 'public_key' => ChefZero::PUBLIC_KEY } it 'knife upload adds the new files' do knife('upload /').should_succeed < /USAGE/ end end end end when_the_chef_server 'is empty' do when_the_repository 'has a data bag item' do file 'data_bags/x/y.json', { 'foo' => 'bar' } it 'knife upload of the data bag uploads only the values in the data bag item and no other' do knife('upload /data_bags/x/y.json').should_succeed < false).keys.sort.should == [ 'foo', 'id' ] end it 'knife upload /data_bags/x /data_bags/x/y.json uploads x once' do knife('upload /data_bags/x /data_bags/x/y.json').should_succeed < 'aaa', 'data_bag' => 'bbb' } it 'upload preserves chef_type and data_bag' do knife('upload /data_bags/x/y.json').should_succeed < false) result.keys.sort.should == [ 'chef_type', 'data_bag', 'id' ] result['chef_type'].should == 'aaa' result['data_bag'].should == 'bbb' end end # Test upload of an item when the other end doesn't even have the container when_the_repository 'has two data bag items' do file 'data_bags/x/y.json', {} file 'data_bags/x/z.json', {} it 'knife upload of one data bag item itself succeeds' do knife('upload /data_bags/x/y.json').should_succeed < {}, 'modified' => {}, 'unmodified' => {} } when_the_repository 'has a modified, unmodified, added and deleted data bag item' do file 'data_bags/x/added.json', {} file 'data_bags/x/modified.json', { 'foo' => 'bar' } file 'data_bags/x/unmodified.json', {} it 'knife upload of the modified file succeeds' do knife('upload /data_bags/x/modified.json').should_succeed < /USAGE/ end it 'knife upload --purge . uploads everything' do knife('upload --purge .').should_succeed < 'version "1.0.0"', 'z.rb' => '' } when_the_repository 'has a modified, extra and missing file for the cookbook' do file 'cookbooks/x/metadata.rb', 'version "1.0.0"' file 'cookbooks/x/y.rb', 'hi' it 'knife upload of any individual file fails' do knife('upload /cookbooks/x/metadata.rb').should_fail "ERROR: /cookbooks/x/metadata.rb cannot be updated.\n" knife('upload /cookbooks/x/y.rb').should_fail "ERROR: /cookbooks/x cannot have a child created under it.\n" knife('upload --purge /cookbooks/x/z.rb').should_fail "ERROR: /cookbooks/x/z.rb cannot be deleted.\n" end # TODO this is a bit of an inconsistency: if we didn't specify --purge, # technically we shouldn't have deleted missing files. But ... cookbooks # are a special case. it 'knife upload of the cookbook itself succeeds' do knife('upload /cookbooks/x').should_succeed < 'version "1.0.0"' }, :frozen => true when_the_repository 'has an update to said cookbook' do file 'cookbooks/frozencook/metadata.rb', 'version "1.0.0" # This is different' it 'knife upload fails to upload the frozen cookbook' do knife('upload /cookbooks/frozencook').should_fail "ERROR: /cookbooks failed to write: Cookbook frozencook is frozen\n" end it 'knife upload --force uploads the frozen cookbook' do knife('upload --force /cookbooks/frozencook').should_succeed < 'version "1.0.0"', 'onlyin1.0.0.rb' => '' } cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => 'hi' } it 'knife upload /cookbooks/x uploads the local version' do knife('diff --name-status /cookbooks').should_succeed < 'version "1.0.0"', 'onlyin1.0.0.rb' => ''} cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => 'hi' } it 'knife upload /cookbooks/x uploads the local version' do knife('upload --purge /cookbooks/x').should_succeed < 'version "1.0.1"', 'onlyin1.0.1.rb' => 'hi' } it 'knife upload /cookbooks/x uploads the local version' do knife('diff --name-status /cookbooks').should_succeed < 'version "0.9.9"', 'onlyin0.9.9.rb' => 'hi' } it 'knife upload /cookbooks/x uploads the new version' do knife('upload --purge /cookbooks/x').should_succeed < "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: A JSON text must at least contain two octets!\n" end end when_the_repository 'has the same environment with the wrong name in the file' do file 'environments/x.json', { 'name' => 'y' } it 'knife upload fails' do knife('upload /environments/x.json').should_fail "ERROR: /environments/x.json failed to write: Name must be 'x' (is 'y')\n" knife('diff --name-status /environments/x.json').should_succeed "M\t/environments/x.json\n" end end when_the_repository 'has the same environment with no name in the file' do file 'environments/x.json', { 'description' => 'hi' } it 'knife upload succeeds' do knife('upload /environments/x.json').should_succeed "Updated /environments/x.json\n" knife('diff --name-status /environments/x.json').should_succeed '' end end end when_the_chef_server 'is empty' do when_the_repository 'has an environment with bad JSON' do file 'environments/x.json', '{' it 'knife upload tries and fails' do knife('upload /environments/x.json').should_fail "ERROR: /environments failed to create_child: Parse error reading JSON creating child 'x.json': A JSON text must at least contain two octets!\n" knife('diff --name-status /environments/x.json').should_succeed "A\t/environments/x.json\n" end end when_the_repository 'has an environment with the wrong name in the file' do file 'environments/x.json', { 'name' => 'y' } it 'knife upload fails' do knife('upload /environments/x.json').should_fail "ERROR: /environments failed to create_child: Error creating 'x.json': Name must be 'x' (is 'y')\n" knife('diff --name-status /environments/x.json').should_succeed "A\t/environments/x.json\n" end end when_the_repository 'has an environment with no name in the file' do file 'environments/x.json', { 'description' => 'hi' } it 'knife upload succeeds' do knife('upload /environments/x.json').should_succeed "Created /environments/x.json\n" knife('diff --name-status /environments/x.json').should_succeed '' end end when_the_repository 'has a data bag with no id in the file' do file 'data_bags/bag/x.json', { 'foo' => 'bar' } it 'knife upload succeeds' do knife('upload /data_bags/bag/x.json').should_succeed "Created /data_bags/bag\nCreated /data_bags/bag/x.json\n" knife('diff --name-status /data_bags/bag/x.json').should_succeed '' end end end end # without versioned cookbooks with_versioned_cookbooks do when_the_chef_server "has one of each thing" do client 'x', {} cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"' } data_bag 'x', { 'y' => {} } environment 'x', {} node 'x', {} role 'x', {} user 'x', {} when_the_repository 'has only top-level directories' do directory 'clients' directory 'cookbooks' directory 'data_bags' directory 'environments' directory 'nodes' directory 'roles' directory 'users' it 'knife upload does nothing' do knife('upload /').should_succeed '' knife('diff --name-status /').should_succeed < "WARNING: /environments/_default.json cannot be deleted (default environment cannot be modified).\n") Deleted extra entry /clients/chef-validator.json (purge is on) Deleted extra entry /clients/chef-webui.json (purge is on) Deleted extra entry /clients/x.json (purge is on) Deleted extra entry /cookbooks/x-1.0.0 (purge is on) Deleted extra entry /data_bags/x (purge is on) Deleted extra entry /environments/x.json (purge is on) Deleted extra entry /nodes/x.json (purge is on) Deleted extra entry /roles/x.json (purge is on) Deleted extra entry /users/admin.json (purge is on) Deleted extra entry /users/x.json (purge is on) EOM knife('diff --name-status /').should_succeed < true, 'public_key' => ChefZero::PUBLIC_KEY } file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY } file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY } file 'cookbooks/x-1.0.0/metadata.rb', 'version "1.0.0"' file 'data_bags/x/y.json', {} file 'environments/_default.json', { 'description' => 'The default Chef environment' } file 'environments/x.json', {} file 'nodes/x.json', {} file 'roles/x.json', {} file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY } file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY } it 'knife upload makes no changes' do knife('upload /cookbooks/x-1.0.0').should_succeed '' knife('diff --name-status /').should_succeed '' end it 'knife upload --purge makes no changes' do knife('upload --purge /').should_succeed '' knife('diff --name-status /').should_succeed '' end context 'except the role file' do file 'roles/x.json', { 'description' => 'blarghle' } it 'knife upload changes the role' do knife('upload /').should_succeed "Updated /roles/x.json\n" knife('diff --name-status /').should_succeed '' end end context 'except the role file is textually different, but not ACTUALLY different' do file 'roles/x.json', < ChefZero::PUBLIC_KEY } file 'cookbooks/x-1.0.0/blah.rb', '' file 'cookbooks/x-2.0.0/metadata.rb', 'version "2.0.0"' file 'cookbooks/y-1.0.0/metadata.rb', 'version "1.0.0"' file 'data_bags/x/z.json', {} file 'data_bags/y/zz.json', {} file 'environments/y.json', {} file 'nodes/y.json', {} file 'roles/y.json', {} file 'users/y.json', { 'public_key' => ChefZero::PUBLIC_KEY } it 'knife upload adds the new files' do knife('upload /').should_succeed < /USAGE/ end end end end # Test upload of an item when the other end doesn't even have the container when_the_chef_server 'is empty' do when_the_repository 'has two data bag items' do file 'data_bags/x/y.json', {} file 'data_bags/x/z.json', {} it 'knife upload of one data bag item itself succeeds' do knife('upload /data_bags/x/y.json').should_succeed < {}, 'modified' => {}, 'unmodified' => {} } when_the_repository 'has a modified, unmodified, added and deleted data bag item' do file 'data_bags/x/added.json', {} file 'data_bags/x/modified.json', { 'foo' => 'bar' } file 'data_bags/x/unmodified.json', {} it 'knife upload of the modified file succeeds' do knife('upload /data_bags/x/modified.json').should_succeed < /USAGE/ end it 'knife upload --purge . uploads everything' do knife('upload --purge .').should_succeed < 'version "1.0.0"', 'z.rb' => '' } when_the_repository 'has a modified, extra and missing file for the cookbook' do file 'cookbooks/x-1.0.0/metadata.rb', 'version "1.0.0"' file 'cookbooks/x-1.0.0/y.rb', 'hi' it 'knife upload of any individual file fails' do knife('upload /cookbooks/x-1.0.0/metadata.rb').should_fail "ERROR: /cookbooks/x-1.0.0/metadata.rb cannot be updated.\n" knife('upload /cookbooks/x-1.0.0/y.rb').should_fail "ERROR: /cookbooks/x-1.0.0 cannot have a child created under it.\n" knife('upload --purge /cookbooks/x-1.0.0/z.rb').should_fail "ERROR: /cookbooks/x-1.0.0/z.rb cannot be deleted.\n" end # TODO this is a bit of an inconsistency: if we didn't specify --purge, # technically we shouldn't have deleted missing files. But ... cookbooks # are a special case. it 'knife upload of the cookbook itself succeeds' do knife('upload /cookbooks/x-1.0.0').should_succeed < 'version "1.0.0"', 'onlyin1.0.0.rb' => '' } cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => 'hi' } it 'knife upload /cookbooks uploads the local version' do knife('diff --name-status /cookbooks').should_succeed < 'version "1.0.0"', 'onlyin1.0.0.rb' => ''} cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => 'hi' } it 'knife upload /cookbooks uploads the local version' do knife('upload --purge /cookbooks').should_succeed < 'version "1.0.1"', 'onlyin1.0.1.rb' => 'hi' } it 'knife upload /cookbooks/x uploads the local version' do knife('diff --name-status /cookbooks').should_succeed < 'version "0.9.9"', 'onlyin0.9.9.rb' => 'hi' } it 'knife upload /cookbooks/x uploads the new version' do knife('upload --purge /cookbooks').should_succeed < "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: A JSON text must at least contain two octets!\n" end end when_the_repository 'has the same environment with the wrong name in the file' do file 'environments/x.json', { 'name' => 'y' } it 'knife upload fails' do knife('upload /environments/x.json').should_fail "ERROR: /environments/x.json failed to write: Name must be 'x' (is 'y')\n" knife('diff --name-status /environments/x.json').should_succeed "M\t/environments/x.json\n" end end when_the_repository 'has the same environment with no name in the file' do file 'environments/x.json', { 'description' => 'hi' } it 'knife upload succeeds' do knife('upload /environments/x.json').should_succeed "Updated /environments/x.json\n" knife('diff --name-status /environments/x.json').should_succeed '' end end end when_the_chef_server 'is empty' do when_the_repository 'has an environment with bad JSON' do file 'environments/x.json', '{' it 'knife upload tries and fails' do knife('upload /environments/x.json').should_fail "ERROR: /environments failed to create_child: Parse error reading JSON creating child 'x.json': A JSON text must at least contain two octets!\n" knife('diff --name-status /environments/x.json').should_succeed "A\t/environments/x.json\n" end end when_the_repository 'has an environment with the wrong name in the file' do file 'environments/x.json', { 'name' => 'y' } it 'knife upload fails' do knife('upload /environments/x.json').should_fail "ERROR: /environments failed to create_child: Error creating 'x.json': Name must be 'x' (is 'y')\n" knife('diff --name-status /environments/x.json').should_succeed "A\t/environments/x.json\n" end end when_the_repository 'has an environment with no name in the file' do file 'environments/x.json', { 'description' => 'hi' } it 'knife upload succeeds' do knife('upload /environments/x.json').should_succeed "Created /environments/x.json\n" knife('diff --name-status /environments/x.json').should_succeed '' end end when_the_repository 'has a data bag with no id in the file' do file 'data_bags/bag/x.json', { 'foo' => 'bar' } it 'knife upload succeeds' do knife('upload /data_bags/bag/x.json').should_succeed "Created /data_bags/bag\nCreated /data_bags/bag/x.json\n" knife('diff --name-status /data_bags/bag/x.json').should_succeed '' end end end end # with versioned cookbooks when_the_chef_server 'has a user' do user 'x', {} when_the_repository 'has the same user with json_class in it' do file 'users/x.json', { 'admin' => true, 'json_class' => 'Chef::WebUIUser' } it 'knife upload /users/x.json succeeds' do knife('upload /users/x.json').should_succeed "Updated /users/x.json\n" end end end end chef-11.8.2/spec/integration/knife/raw_spec.rb0000644000004100000410000001251112254362222021241 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'support/shared/integration/integration_helper' require 'chef/knife/raw' require 'chef/knife/show' describe 'knife raw' do extend IntegrationSupport include KnifeSupport when_the_chef_server "has one of each thing" do client 'x', '{}' cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"' } data_bag 'x', { 'y' => '{}' } environment 'x', '{}' node 'x', '{}' role 'x', '{}' user 'x', '{}' it 'knife raw /nodes/x returns the node', :pending => (RUBY_VERSION < "1.9") do knife('raw /nodes/x').should_succeed < (RUBY_VERSION < "1.9") do knife('raw -m DELETE /roles/x').should_succeed < (RUBY_VERSION < "1.9") do Tempfile.open('raw_put_input') do |file| file.write < (RUBY_VERSION < "1.9") do Tempfile.open('raw_put_input') do |file| file.write < 'application/json' }, ['{ "x": "y", "a": "b" }'] ] end @raw_server = Puma::Server.new(app, Puma::Events.new(STDERR, STDOUT)) @raw_server.add_tcp_listener("127.0.0.1", 9018) @raw_server.run end after :each do Chef::Config.chef_server_url = @real_chef_server_url @raw_server.stop(true) end it 'knife raw /blah returns the prettified json', :pending => (RUBY_VERSION < "1.9") do knife('raw /blah').should_succeed < 'text' }, ['{ "x": "y", "a": "b" }'] ] end @raw_server = Puma::Server.new(app, Puma::Events.new(STDERR, STDOUT)) @raw_server.add_tcp_listener("127.0.0.1", 9018) @raw_server.run end after :each do Chef::Config.chef_server_url = @real_chef_server_url @raw_server.stop(true) end it 'knife raw /blah returns the raw text' do knife('raw /blah').should_succeed(<) # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'support/shared/integration/integration_helper' require 'chef/knife/list' require 'chef/knife/show' describe 'chefignore tests' do extend IntegrationSupport include KnifeSupport when_the_repository "has lots of stuff in it" do file 'roles/x.json', {} file 'environments/x.json', {} file 'data_bags/bag1/x.json', {} file 'cookbooks/cookbook1/x.json', {} context "and has a chefignore everywhere except cookbooks" do chefignore = "x.json\nroles/x.json\nenvironments/x.json\ndata_bags/bag1/x.json\nbag1/x.json\ncookbooks/cookbook1/x.json\ncookbook1/x.json\n" file 'chefignore', chefignore file 'roles/chefignore', chefignore file 'environments/chefignore', chefignore file 'data_bags/chefignore', chefignore file 'data_bags/bag1/chefignore', chefignore file 'cookbooks/cookbook1/chefignore', chefignore it 'nothing is ignored' do # NOTE: many of the "chefignore" files should probably not show up # themselves, but we have other tests that talk about that knife('list --local -Rfp /').should_succeed < "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n") /cookbooks/ EOM end end when_the_repository "has multiple cookbooks" do file 'cookbooks/cookbook1/x.json', {} file 'cookbooks/cookbook1/y.json', {} file 'cookbooks/cookbook2/x.json', {} file 'cookbooks/cookbook2/y.json', {} context 'and has a chefignore with filenames' do file 'cookbooks/chefignore', "x.json\n" it 'matching files and directories get ignored in all cookbooks' do knife('list --local -Rfp /').should_succeed < "WARN: Child with name 'yourcookbook' found in multiple directories: #{Chef::Config.chef_repo_path}/cookbooks1/yourcookbook and #{Chef::Config.chef_repo_path}/cookbooks2/yourcookbook\n") /cookbooks/ /cookbooks/mycookbook/ /cookbooks/mycookbook/x.json /cookbooks/yourcookbook/ /cookbooks/yourcookbook/onlyincookbooks1.rb /cookbooks/yourcookbook/x.json EOM end end end end when_the_repository 'has a cookbook named chefignore' do file 'cookbooks/chefignore/metadata.rb', {} it 'knife list -Rfp /cookbooks shows it' do knife('list --local -Rfp /cookbooks').should_succeed <) # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'support/shared/integration/integration_helper' require 'chef/knife/download' require 'chef/knife/diff' describe 'knife download' do extend IntegrationSupport include KnifeSupport context 'without versioned cookbooks' do when_the_chef_server "has one of each thing" do client 'x', {} cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"' } data_bag 'x', { 'y' => {} } environment 'x', {} node 'x', {} role 'x', {} user 'x', {} when_the_repository 'has only top-level directories' do directory 'clients' directory 'cookbooks' directory 'data_bags' directory 'environments' directory 'nodes' directory 'roles' directory 'users' it 'knife download downloads everything' do knife('download /').should_succeed < true, 'public_key' => ChefZero::PUBLIC_KEY } file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY } file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY } file 'cookbooks/x/metadata.rb', 'version "1.0.0"' file 'data_bags/x/y.json', {} file 'environments/_default.json', { "description" => "The default Chef environment" } file 'environments/x.json', {} file 'nodes/x.json', {} file 'roles/x.json', {} file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY } file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY } it 'knife download makes no changes' do knife('download /').should_succeed '' knife('diff --name-status /').should_succeed '' end it 'knife download --purge makes no changes' do knife('download --purge /').should_succeed '' knife('diff --name-status /').should_succeed '' end context 'except the role file' do file 'roles/x.json', < ChefZero::PUBLIC_KEY } file 'cookbooks/x/blah.rb', '' file 'cookbooks/y/metadata.rb', 'version "1.0.0"' file 'data_bags/x/z.json', {} file 'data_bags/y/zz.json', {} file 'environments/y.json', {} file 'nodes/y.json', {} file 'roles/y.json', {} file 'users/y.json', { 'public_key' => ChefZero::PUBLIC_KEY } it 'knife download does nothing' do knife('download /').should_succeed '' knife('diff --name-status /').should_succeed < /USAGE/ end end end end # Test download of an item when the other end doesn't even have the container when_the_repository 'is empty' do when_the_chef_server 'has two data bag items' do data_bag 'x', { 'y' => {}, 'z' => {} } it 'knife download of one data bag item itself succeeds' do knife('download /data_bags/x/y.json').should_succeed < {}, 'modified' => { 'foo' => 'bar' }, 'unmodified' => {} } it 'knife download of the modified file succeeds' do knife('download /data_bags/x/modified.json').should_succeed < /USAGE/ end it 'knife download --purge . downloads everything' do knife('download --purge .').should_succeed < 'version "1.0.0"', 'y.rb' => 'hi' } it 'knife download of a modified file succeeds' do knife('download /cookbooks/x/metadata.rb').should_succeed "Updated /cookbooks/x/metadata.rb\n" knife('diff --name-status /cookbooks').should_succeed < 'version "1.0.0"', 'onlyin1.0.0.rb' => '' } cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => 'hi' } it 'knife download /cookbooks/x downloads the latest version' do knife('download --purge /cookbooks/x').should_succeed < 'version "1.0.0"', 'onlyin1.0.0.rb' => ''} cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => 'hi' } it 'knife download /cookbooks/x downloads the updated file' do knife('download --purge /cookbooks/x').should_succeed < 'version "1.0.1"', 'onlyin1.0.1.rb' => 'hi' } it 'knife download /cookbooks/x downloads the latest version' do knife('download --purge /cookbooks/x').should_succeed < 'version "0.9.9"', 'onlyin0.9.9.rb' => 'hi' } it 'knife download /cookbooks/x downloads the old version' do knife('download --purge /cookbooks/x').should_succeed < "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: A JSON text must at least contain two octets!\n" knife('diff --name-status /environments/x.json').should_succeed '' end end when_the_repository 'has the same environment with the wrong name in the file' do file 'environments/x.json', { 'name' => 'y' } it 'knife download succeeds' do knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n" knife('diff --name-status /environments/x.json').should_succeed '' end end when_the_repository 'has the same environment with no name in the file' do file 'environments/x.json', { 'description' => 'hi' } it 'knife download succeeds' do knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n" knife('diff --name-status /environments/x.json').should_succeed '' end end end end # without versioned cookbooks with_versioned_cookbooks do when_the_chef_server "has one of each thing" do client 'x', {} cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"' } data_bag 'x', { 'y' => {} } environment 'x', {} node 'x', {} role 'x', {} user 'x', {} when_the_repository 'has only top-level directories' do directory 'clients' directory 'cookbooks' directory 'data_bags' directory 'environments' directory 'nodes' directory 'roles' directory 'users' it 'knife download downloads everything' do knife('download /').should_succeed < true, 'public_key' => ChefZero::PUBLIC_KEY } file 'clients/chef-webui.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY } file 'clients/x.json', { 'public_key' => ChefZero::PUBLIC_KEY } file 'cookbooks/x-1.0.0/metadata.rb', 'version "1.0.0"' file 'data_bags/x/y.json', {} file 'environments/_default.json', { "description" => "The default Chef environment" } file 'environments/x.json', {} file 'nodes/x.json', {} file 'roles/x.json', {} file 'users/admin.json', { 'admin' => true, 'public_key' => ChefZero::PUBLIC_KEY } file 'users/x.json', { 'public_key' => ChefZero::PUBLIC_KEY } it 'knife download makes no changes' do knife('download /').should_succeed '' knife('diff --name-status /').should_succeed '' end it 'knife download --purge makes no changes' do knife('download --purge /').should_succeed '' knife('diff --name-status /').should_succeed '' end context 'except the role file' do file 'roles/x.json', { "description" => "blarghle" } it 'knife download changes the role' do knife('download /').should_succeed "Updated /roles/x.json\n" knife('diff --name-status /').should_succeed '' end end context 'except the role file is textually different, but not ACTUALLY different' do file 'roles/x.json', < ChefZero::PUBLIC_KEY } file 'cookbooks/x-1.0.0/blah.rb', '' file 'cookbooks/x-2.0.0/metadata.rb', 'version "2.0.0"' file 'cookbooks/y-1.0.0/metadata.rb', 'version "1.0.0"' file 'data_bags/x/z.json', {} file 'data_bags/y/zz.json', {} file 'environments/y.json', {} file 'nodes/y.json', {} file 'roles/y.json', {} file 'users/y.json', { 'public_key' => ChefZero::PUBLIC_KEY } it 'knife download does nothing' do knife('download /').should_succeed '' knife('diff --name-status /').should_succeed < /USAGE/ end end end end # Test download of an item when the other end doesn't even have the container when_the_repository 'is empty' do when_the_chef_server 'has two data bag items' do data_bag 'x', { 'y' => {}, 'z' => {} } it 'knife download of one data bag item itself succeeds' do knife('download /data_bags/x/y.json').should_succeed < {}, 'modified' => { 'foo' => 'bar' }, 'unmodified' => {} } it 'knife download of the modified file succeeds' do knife('download /data_bags/x/modified.json').should_succeed < /USAGE/ end it 'knife download --purge . downloads everything' do knife('download --purge .').should_succeed < 'version "1.0.0"', 'y.rb' => 'hi' } it 'knife download of a modified file succeeds' do knife('download /cookbooks/x-1.0.0/metadata.rb').should_succeed "Updated /cookbooks/x-1.0.0/metadata.rb\n" knife('diff --name-status /cookbooks').should_succeed < 'version "1.0.0"', 'onlyin1.0.0.rb' => '' } cookbook 'x', '1.0.1', { 'metadata.rb' => 'version "1.0.1"', 'onlyin1.0.1.rb' => 'hi' } it 'knife download /cookbooks/x downloads the latest version' do knife('download --purge /cookbooks').should_succeed < 'version "1.0.0"', 'onlyin1.0.0.rb' => ''} cookbook 'x', '0.9.9', { 'metadata.rb' => 'version "0.9.9"', 'onlyin0.9.9.rb' => 'hi' } it 'knife download /cookbooks downloads the updated file' do knife('download --purge /cookbooks').should_succeed < 'version "1.0.1"', 'onlyin1.0.1.rb' => 'hi' } it 'knife download /cookbooks/x downloads the latest version' do knife('download --purge /cookbooks').should_succeed < 'version "0.9.9"', 'onlyin0.9.9.rb' => 'hi' } it 'knife download --purge /cookbooks downloads the old version and deletes the new version' do knife('download --purge /cookbooks').should_succeed < "WARN: Parse error reading #{path_to('environments/x.json')} as JSON: A JSON text must at least contain two octets!\n" knife('diff --name-status /environments/x.json').should_succeed '' end end when_the_repository 'has the same environment with the wrong name in the file' do file 'environments/x.json', { 'name' => 'y' } it 'knife download succeeds' do knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n" knife('diff --name-status /environments/x.json').should_succeed '' end end when_the_repository 'has the same environment with no name in the file' do file 'environments/x.json', { 'description' => 'hi' } it 'knife download succeeds' do knife('download /environments/x.json').should_succeed "Updated /environments/x.json\n" knife('diff --name-status /environments/x.json').should_succeed '' end end end end # with versioned cookbooks when_the_chef_server 'has a cookbook' do cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"' } when_the_repository 'is empty' do it 'knife download /cookbooks/x signs all requests' do # Check that BasicClient.request() always gets called with X-OPS-USERID original_new = Chef::HTTP::BasicClient.method(:new) Chef::HTTP::BasicClient.should_receive(:new) do |args| new_result = original_new.call(*args) original_request = new_result.method(:request) new_result.should_receive(:request) do |method, url, body, headers, &response_handler| headers['X-OPS-USERID'].should_not be_nil original_request.call(method, url, body, headers, &response_handler) end.at_least(:once) new_result end.at_least(:once) knife('download /cookbooks/x').should_succeed <) # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'puma' require 'support/shared/integration/integration_helper' require 'chef/knife/list' describe 'redirection' do extend IntegrationSupport include KnifeSupport when_the_chef_server 'has a role' do role 'x', {} context 'and another server redirects to it with 302' do before :each do @real_chef_server_url = Chef::Config.chef_server_url Chef::Config.chef_server_url = "http://127.0.0.1:9018" app = lambda do |env| [302, {'Content-Type' => 'text','Location' => "#{@real_chef_server_url}#{env['PATH_INFO']}" }, ['302 found'] ] end @redirector_server = Puma::Server.new(app, Puma::Events.new(STDERR, STDOUT)) @redirector_server.add_tcp_listener("127.0.0.1", 9018) @redirector_server.run Timeout::timeout(5) do until @redirector_server.running sleep(0.01) end raise @server_error if @server_error end end after :each do Chef::Config.chef_server_url = @real_chef_server_url @redirector_server.stop(true) end it 'knife list /roles returns the role' do knife('list /roles').should_succeed "/roles/x.json\n" end end end end chef-11.8.2/spec/integration/knife/show_spec.rb0000644000004100000410000001144312254362222021433 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'support/shared/integration/integration_helper' require 'chef/knife/show' describe 'knife show' do extend IntegrationSupport include KnifeSupport when_the_chef_server "has one of each thing" do client 'x', '{}' cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"' } data_bag 'x', { 'y' => '{}' } environment 'x', '{}' node 'x', '{}' role 'x', '{}' user 'x', '{}' when_the_repository 'also has one of each thing' do file 'clients/x.json', { 'foo' => 'bar' } file 'cookbooks/x/metadata.rb', 'version "1.0.1"' file 'data_bags/x/y.json', { 'foo' => 'bar' } file 'environments/_default.json', { 'foo' => 'bar' } file 'environments/x.json', { 'foo' => 'bar' } file 'nodes/x.json', { 'foo' => 'bar' } file 'roles/x.json', { 'foo' => 'bar' } file 'users/x.json', { 'foo' => 'bar' } it 'knife show /cookbooks/x/metadata.rb shows the remote version' do knife('show /cookbooks/x/metadata.rb').should_succeed < (RUBY_VERSION < "1.9") do knife('show /environments/x.json').should_succeed < (RUBY_VERSION < "1.9") do knife('show /roles/x.json').should_succeed < { 'foo' => 'bar' }, 'cookbook_versions' => { 'blah' => '= 1.0.0'}, 'override_attributes' => { 'x' => 'y' }, 'description' => 'woo', 'name' => 'x' } it 'knife show shows the attributes in a predetermined order', :pending => (RUBY_VERSION < "1.9") do knife('show /environments/x.json').should_succeed < chef_dir) result.error! result.stdout.should include("ITWORKS") end it "should evaluate its node.json file" do file 'config/solo.rb', < chef_dir) result.error! result.stdout.should include("ITWORKS") end end when_the_repository "has a cookbook with a recipe with sleep" do directory 'logs' file 'logs/runs.log', '' file 'cookbooks/x/metadata.rb', 'version "1.0.0"' file 'cookbooks/x/recipes/default.rb', < true do file 'config/solo.rb', < chef_dir) # Give it some time to progress sleep 1 # Instantiate the second chef-solo run s2 = Process.spawn("ruby bin/chef-solo -c \"#{path_to('config/solo.rb')}\" -o 'x::default' \ -l debug -L #{path_to('logs/runs.log')}", :chdir => chef_dir) Process.waitpid(s1) Process.waitpid(s2) end }.should_not raise_error(Timeout::Error) # Unfortunately file / directory helpers in integration tests # are implemented using before(:each) so we need to do all below # checks in one example. run_log = File.read(path_to('logs/runs.log')) # both of the runs should succeed run_log.lines.reject {|l| !l.include? "INFO: Chef Run complete in"}.length.should == 2 # second run should have a message which indicates it's waiting for the first run pid_lines = run_log.lines.reject {|l| !l.include? "Chef-client pid:"} pid_lines.length.should == 2 pids = pid_lines.map {|l| l.split(" ").last} run_log.should include("Chef client #{pids[0]} is running, will wait for it to finish and then run.") # second run should start after first run ends starts = [ ] ends = [ ] run_log.lines.each_with_index do |line, index| if line.include? "Chef-client pid:" starts << index elsif line.include? "INFO: Chef Run complete in" ends << index end end starts[1].should > ends[0] end end end chef-11.8.2/spec/unit/0000755000004100000410000000000012254362222014451 5ustar www-datawww-datachef-11.8.2/spec/unit/mixin/0000755000004100000410000000000012254362222015575 5ustar www-datawww-datachef-11.8.2/spec/unit/mixin/params_validate_spec.rb0000644000004100000410000002536212254362222022300 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' class TinyClass include Chef::Mixin::ParamsValidate def music(is_good=true) is_good end end describe Chef::Mixin::ParamsValidate do before(:each) do @vo = TinyClass.new() end it "should allow a hash and a hash as arguments to validate" do lambda { @vo.validate({:one => "two"}, {}) }.should_not raise_error(ArgumentError) end it "should raise an argument error if validate is called incorrectly" do lambda { @vo.validate("one", "two") }.should raise_error(ArgumentError) end it "should require validation map keys to be symbols or strings" do lambda { @vo.validate({:one => "two"}, { :one => true }) }.should_not raise_error(ArgumentError) lambda { @vo.validate({:one => "two"}, { "one" => true }) }.should_not raise_error(ArgumentError) lambda { @vo.validate({:one => "two"}, { Hash.new => true }) }.should raise_error(ArgumentError) end it "should allow options to be required with true" do lambda { @vo.validate({:one => "two"}, { :one => true }) }.should_not raise_error(ArgumentError) end it "should allow options to be optional with false" do lambda { @vo.validate({}, {:one => false})}.should_not raise_error(ArgumentError) end it "should allow you to check what kind_of? thing an argument is with kind_of" do lambda { @vo.validate( {:one => "string"}, { :one => { :kind_of => String } } ) }.should_not raise_error(ArgumentError) lambda { @vo.validate( {:one => "string"}, { :one => { :kind_of => Array } } ) }.should raise_error(ArgumentError) end it "should allow you to specify an argument is required with required" do lambda { @vo.validate( {:one => "string"}, { :one => { :required => true } } ) }.should_not raise_error(ArgumentError) lambda { @vo.validate( {:two => "string"}, { :one => { :required => true } } ) }.should raise_error(ArgumentError) lambda { @vo.validate( {:two => "string"}, { :one => { :required => false } } ) }.should_not raise_error(ArgumentError) end it "should allow you to specify whether an object has a method with respond_to" do lambda { @vo.validate( {:one => @vo}, { :one => { :respond_to => "validate" } } ) }.should_not raise_error(ArgumentError) lambda { @vo.validate( {:one => @vo}, { :one => { :respond_to => "monkey" } } ) }.should raise_error(ArgumentError) end it "should allow you to specify whether an object has all the given methods with respond_to and an array" do lambda { @vo.validate( {:one => @vo}, { :one => { :respond_to => ["validate", "music"] } } ) }.should_not raise_error(ArgumentError) lambda { @vo.validate( {:one => @vo}, { :one => { :respond_to => ["monkey", "validate"] } } ) }.should raise_error(ArgumentError) end it "should let you set a default value with default => value" do arguments = Hash.new @vo.validate(arguments, { :one => { :default => "is the loneliest number" } }) arguments[:one].should == "is the loneliest number" end it "should let you check regular expressions" do lambda { @vo.validate( { :one => "is good" }, { :one => { :regex => /^is good$/ } } ) }.should_not raise_error(ArgumentError) lambda { @vo.validate( { :one => "is good" }, { :one => { :regex => /^is bad$/ } } ) }.should raise_error(ArgumentError) end it "should let you specify your own callbacks" do lambda { @vo.validate( { :one => "is good" }, { :one => { :callbacks => { "should be equal to is good" => lambda { |a| a == "is good" }, } } } ) }.should_not raise_error(ArgumentError) lambda { @vo.validate( { :one => "is bad" }, { :one => { :callbacks => { "should be equal to 'is good'" => lambda { |a| a == "is good" }, } } } ) }.should raise_error(ArgumentError) end it "should let you combine checks" do args = { :one => "is good", :two => "is bad" } lambda { @vo.validate( args, { :one => { :kind_of => String, :respond_to => [ :to_s, :upcase ], :regex => /^is good/, :callbacks => { "should be your friend" => lambda { |a| a == "is good" } }, :required => true }, :two => { :kind_of => String, :required => false }, :three => { :default => "neato mosquito" } } ) }.should_not raise_error(ArgumentError) args[:three].should == "neato mosquito" lambda { @vo.validate( args, { :one => { :kind_of => String, :respond_to => [ :to_s, :upcase ], :regex => /^is good/, :callbacks => { "should be your friend" => lambda { |a| a == "is good" } }, :required => true }, :two => { :kind_of => Hash, :required => false }, :three => { :default => "neato mosquito" } } ) }.should raise_error(ArgumentError) end it "should raise an ArgumentError if the validation map has an unknown check" do lambda { @vo.validate( { :one => "two" }, { :one => { :busted => "check" } } ) }.should raise_error(ArgumentError) end it "should accept keys that are strings in the options" do lambda { @vo.validate({ "one" => "two" }, { :one => { :regex => /^two$/ }}) }.should_not raise_error(ArgumentError) end it "should allow an array to kind_of" do lambda { @vo.validate( {:one => "string"}, { :one => { :kind_of => [ String, Array ] } } ) }.should_not raise_error(ArgumentError) lambda { @vo.validate( {:one => ["string"]}, { :one => { :kind_of => [ String, Array ] } } ) }.should_not raise_error(ArgumentError) lambda { @vo.validate( {:one => Hash.new}, { :one => { :kind_of => [ String, Array ] } } ) }.should raise_error(ArgumentError) end it "asserts that a value returns false from a predicate method" do lambda do @vo.validate({:not_blank => "should pass"}, {:not_blank => {:cannot_be => :nil, :cannot_be => :empty}}) end.should_not raise_error lambda do @vo.validate({:not_blank => ""}, {:not_blank => {:cannot_be => :nil, :cannot_be => :empty}}) end.should raise_error(Chef::Exceptions::ValidationFailed) end it "should set and return a value, then return the same value" do value = "meow" @vo.set_or_return(:test, value, {}).object_id.should == value.object_id @vo.set_or_return(:test, nil, {}).object_id.should == value.object_id end it "should set and return a default value when the argument is nil, then return the same value" do value = "meow" @vo.set_or_return(:test, nil, { :default => value }).object_id.should == value.object_id @vo.set_or_return(:test, nil, {}).object_id.should == value.object_id end it "should raise an ArgumentError when argument is nil and required is true" do lambda { @vo.set_or_return(:test, nil, { :required => true }) }.should raise_error(ArgumentError) end it "should not raise an error when argument is nil and required is false" do lambda { @vo.set_or_return(:test, nil, { :required => false }) }.should_not raise_error(ArgumentError) end it "should set and return @name, then return @name for foo when argument is nil" do value = "meow" @vo.set_or_return(:name, value, { }).object_id.should == value.object_id @vo.set_or_return(:foo, nil, { :name_attribute => true }).object_id.should == value.object_id end it "should allow DelayedEvaluator instance to be set for value regardless of restriction" do value = Chef::DelayedEvaluator.new{ 'test' } @vo.set_or_return(:test, value, {:kind_of => Numeric}) end it "should raise an error when delayed evaluated attribute is not valid" do value = Chef::DelayedEvaluator.new{ 'test' } @vo.set_or_return(:test, value, {:kind_of => Numeric}) lambda do @vo.set_or_return(:test, nil, {:kind_of => Numeric}) end.should raise_error(Chef::Exceptions::ValidationFailed) end it "should create DelayedEvaluator instance when #lazy is used" do @vo.set_or_return(:delayed, @vo.lazy{ 'test' }, {}) @vo.instance_variable_get(:@delayed).should be_a(Chef::DelayedEvaluator) end it "should execute block on each call when DelayedEvaluator" do value = 'fubar' @vo.set_or_return(:test, @vo.lazy{ value }, {}) @vo.set_or_return(:test, nil, {}).should == 'fubar' value = 'foobar' @vo.set_or_return(:test, nil, {}).should == 'foobar' value = 'fauxbar' @vo.set_or_return(:test, nil, {}).should == 'fauxbar' end it "should not evaluate non DelayedEvaluator instances" do value = lambda{ 'test' } @vo.set_or_return(:test, value, {}) @vo.set_or_return(:test, nil, {}).object_id.should == value.object_id @vo.set_or_return(:test, nil, {}).should be_a(Proc) end end chef-11.8.2/spec/unit/mixin/checksum_spec.rb0000644000004100000410000000235312254362222020741 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/mixin/checksum' require 'stringio' class Chef::CMCCheck include Chef::Mixin::Checksum end describe Chef::Mixin::Checksum do before(:each) do @checksum_user = Chef::CMCCheck.new @cache = Chef::Digester.instance @file = CHEF_SPEC_DATA + "/checksum/random.txt" @stat = mock("File::Stat", { :mtime => Time.at(0) }) File.stub!(:stat).and_return(@stat) end it "gets the checksum of a file" do @checksum_user.checksum(@file).should == "09ee9c8cc70501763563bcf9c218d71b2fbf4186bf8e1e0da07f0f42c80a3394" end end chef-11.8.2/spec/unit/mixin/shell_out_spec.rb0000644000004100000410000000706412254362222021141 0ustar www-datawww-data# # Author:: Ho-Sheng Hsiao (hosh@opscode.com) # Code derived from spec/unit/mixin/command_spec.rb # # Original header: # Author:: Hongli Lai (hongli@phusion.nl) # Copyright:: Copyright (c) 2009 Phusion # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Mixin::ShellOut do include Chef::Mixin::ShellOut describe '#run_command_compatible_options' do subject { run_command_compatible_options(command_args) } let(:command_args) { [ cmd, options ] } let(:cmd) { "echo '#{rand(1000)}'" } let(:output) { StringIO.new } let!(:capture_log_output) { Chef::Log.logger = Logger.new(output) } let(:assume_deprecation_log_level) { Chef::Log.stub!(:level).and_return(:warn) } context 'without options' do let(:command_args) { [ cmd ] } it 'should not edit command args' do should eql(command_args) end end context 'without deprecated options' do let(:options) { { :environment => environment } } let(:environment) { { 'LC_ALL' => 'C' } } it 'should not edit command args' do should eql(command_args) end end def self.should_emit_deprecation_warning_about(old_option, new_option) it 'should emit a deprecation warning' do assume_deprecation_log_level and capture_log_output subject output.string.should match /DEPRECATION:/ output.string.should match Regexp.escape(old_option.to_s) output.string.should match Regexp.escape(new_option.to_s) end end context 'with :command_log_level option' do let(:options) { { :command_log_level => command_log_level } } let(:command_log_level) { :warn } it 'should convert :command_log_level to :log_level' do should eql [ cmd, { :log_level => command_log_level } ] end should_emit_deprecation_warning_about :command_log_level, :log_level end context 'with :command_log_prepend option' do let(:options) { { :command_log_prepend => command_log_prepend } } let(:command_log_prepend) { 'PROVIDER:' } it 'should convert :command_log_prepend to :log_tag' do should eql [ cmd, { :log_tag => command_log_prepend } ] end should_emit_deprecation_warning_about :command_log_prepend, :log_tag end context "with 'command_log_level' option" do let(:options) { { 'command_log_level' => command_log_level } } let(:command_log_level) { :warn } it "should convert 'command_log_level' to :log_level" do should eql [ cmd, { :log_level => command_log_level } ] end should_emit_deprecation_warning_about :command_log_level, :log_level end context "with 'command_log_prepend' option" do let(:options) { { 'command_log_prepend' => command_log_prepend } } let(:command_log_prepend) { 'PROVIDER:' } it "should convert 'command_log_prepend' to :log_tag" do should eql [ cmd, { :log_tag => command_log_prepend } ] end should_emit_deprecation_warning_about :command_log_prepend, :log_tag end end end chef-11.8.2/spec/unit/mixin/deprecation_spec.rb0000644000004100000410000000343512254362222021436 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/mixin/deprecation' describe Chef::Mixin do describe "deprecating constants (Class/Module)" do before do Chef::Mixin.deprecate_constant(:DeprecatedClass, Chef::Node, "This is a test deprecation") @log_io = StringIO.new Chef::Log.init(@log_io) end it "has a list of deprecated constants" do Chef::Mixin.deprecated_constants.should have_key(:DeprecatedClass) end it "returns the replacement when accessing the deprecated constant" do Chef::Mixin::DeprecatedClass.should == Chef::Node end it "warns when accessing the deprecated constant" do Chef::Mixin::DeprecatedClass @log_io.string.should include("This is a test deprecation") end end end describe Chef::Mixin::Deprecation::DeprecatedInstanceVariable do before do Chef::Log.logger = Logger.new(StringIO.new) @deprecated_ivar = Chef::Mixin::Deprecation::DeprecatedInstanceVariable.new('value', 'an_ivar') end it "forward method calls to the target object" do @deprecated_ivar.length.should == 5 @deprecated_ivar.to_sym.should == :value end end chef-11.8.2/spec/unit/mixin/enforce_ownership_and_permissions_spec.rb0000644000004100000410000000704012254362222026131 0ustar www-datawww-data# # Author:: Mark Mzyk () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'etc' require 'ostruct' describe Chef::Mixin::EnforceOwnershipAndPermissions do before(:each) do @node = Chef::Node.new @node.name "make_believe" @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @tmpdir = Dir.mktmpdir @resource = Chef::Resource::File.new("#{@tmpdir}/madeup.txt") FileUtils.touch @resource.path @resource.owner "adam" @provider = Chef::Provider::File.new(@resource, @run_context) @provider.current_resource = @resource end after(:each) do FileUtils.rm_rf(@tmpdir) end it "should call set_all on the file access control object" do Chef::FileAccessControl.any_instance.should_receive(:set_all) @provider.enforce_ownership_and_permissions end context "when nothing was updated" do before do Chef::FileAccessControl.any_instance.stub(:uid_from_resource).and_return(0) Chef::FileAccessControl.any_instance.stub(:requires_changes?).and_return(false) Chef::FileAccessControl.any_instance.stub(:define_resource_requirements) passwd_struct = if windows? Struct::Passwd.new("root", "x", 0, 0, "/root", "/bin/bash") else Struct::Passwd.new("root", "x", 0, 0, "root", "/root", "/bin/bash") end group_struct = OpenStruct.new(:name => "root", :passwd => "x", :gid => 0) Etc.stub!(:getpwuid).and_return(passwd_struct) Etc.stub!(:getgrgid).and_return(group_struct) end it "does not set updated_by_last_action on the new resource" do @provider.new_resource.should_not_receive(:updated_by_last_action) Chef::FileAccessControl.any_instance.stub(:set_all) @provider.run_action(:create) end end context "when something was modified" do before do Chef::FileAccessControl.any_instance.stub(:requires_changes?).and_return(true) Chef::FileAccessControl.any_instance.stub(:uid_from_resource).and_return(0) passwd_struct = if windows? Struct::Passwd.new("root", "x", 0, 0, "/root", "/bin/bash") else Struct::Passwd.new("root", "x", 0, 0, "root", "/root", "/bin/bash") end group_struct = OpenStruct.new(:name => "root", :passwd => "x", :gid => 0) Etc.stub!(:getpwuid).and_return(passwd_struct) Etc.stub!(:getgrgid).and_return(group_struct) end it "sets updated_by_last_action on the new resource" do @provider.new_resource.owner(0) # CHEF-3557 hack - Set these because we don't for windows @provider.new_resource.group(0) # CHEF-3557 hack - Set these because we don't for windows @provider.new_resource.should_receive(:updated_by_last_action) Chef::FileAccessControl.any_instance.stub(:set_all) @provider.run_action(:create) end end end chef-11.8.2/spec/unit/mixin/windows_architecture_helper_spec.rb0000644000004100000410000000630712254362222024735 0ustar www-datawww-data# # Author:: Adam Edwards () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/mixin/windows_architecture_helper' describe Chef::Mixin::WindowsArchitectureHelper do include Chef::Mixin::WindowsArchitectureHelper before do @valid_architectures = [ :i386, :x86_64 ] @invalid_architectures = [ "i386", "x86_64", :x64, :x86, :arm ] @node_i386 = Chef::Node.new @node_x86_64 = Chef::Node.new end it "returns true when valid architectures are passed to valid_windows_architecture?" do @valid_architectures.each do | architecture | valid_windows_architecture?(architecture).should == true end end it "returns false when invalid architectures are passed to valid_windows_architecture?" do @invalid_architectures.each do | architecture | valid_windows_architecture?(architecture).should == false end end it "does not raise an exception when a valid architecture is passed to assert_valid_windows_architecture!" do @valid_architectures.each do | architecture | assert_valid_windows_architecture!(architecture) end end it "raises an error if an invalid architecture is passed to assert_valid_windows_architecture!" do @invalid_architectures.each do | architecture | begin assert_valid_windows_architecture!(architecture).should raise_error Chef::Exceptions::Win32ArchitectureIncorrect rescue Chef::Exceptions::Win32ArchitectureIncorrect end end end it "returns true for each supported desired architecture for all nodes with each valid architecture passed to node_supports_windows_architecture" do enumerate_architecture_node_combinations(true) end it "returns false for each unsupported desired architecture for all nodes with each valid architecture passed to node_supports_windows_architecture?" do enumerate_architecture_node_combinations(true) end def enumerate_architecture_node_combinations(only_valid_combinations) @valid_architectures.each do | node_architecture | new_node = Chef::Node.new new_node.default["kernel"] = Hash.new new_node.default["kernel"][:machine] = node_architecture.to_s @valid_architectures.each do | supported_architecture | node_supports_windows_architecture?(new_node, supported_architecture).should == true if only_valid_combinations && (supported_architecture != :x86_64 && node_architecture != :i386 ) node_supports_windows_architecture?(new_node, supported_architecture).should == false if ! only_valid_combinations && (supported_architecture == :x86_64 && node_architecture == :i386 ) end end end end chef-11.8.2/spec/unit/mixin/securable_spec.rb0000644000004100000410000003322312254362222021104 0ustar www-datawww-data# # Author:: Mark Mzyk () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Mixin::Securable do before(:each) do @securable = Object.new @securable.send(:extend, Chef::Mixin::Securable) @securable.send(:extend, Chef::Mixin::ParamsValidate) end it "should accept a group name or id for group" do lambda { @securable.group "root" }.should_not raise_error(ArgumentError) lambda { @securable.group 123 }.should_not raise_error(ArgumentError) lambda { @securable.group "root*goo" }.should raise_error(ArgumentError) end it "should accept a user name or id for owner" do lambda { @securable.owner "root" }.should_not raise_error(ArgumentError) lambda { @securable.owner 123 }.should_not raise_error(ArgumentError) lambda { @securable.owner "root*goo" }.should raise_error(ArgumentError) end it "allows the owner to be specified as #user" do @securable.should respond_to(:user) end describe "unix-specific behavior" do before(:each) do platform_mock :unix do load File.join(File.dirname(__FILE__), "..", "..", "..", "lib", "chef", "config.rb") load File.join(File.dirname(__FILE__), "..", "..", "..", "lib", "chef", "mixin", "securable.rb") @securable = Object.new @securable.send(:extend, Chef::Mixin::Securable) @securable.send(:extend, Chef::Mixin::ParamsValidate) end end it "should accept a group name or id for group with spaces and backslashes" do lambda { @securable.group 'test\ group' }.should_not raise_error(ArgumentError) end it "should accept a unix file mode in string form as an octal number" do lambda { @securable.mode "0" }.should_not raise_error(ArgumentError) lambda { @securable.mode "0000" }.should_not raise_error(ArgumentError) lambda { @securable.mode "0111" }.should_not raise_error(ArgumentError) lambda { @securable.mode "0444" }.should_not raise_error(ArgumentError) lambda { @securable.mode "111" }.should_not raise_error(ArgumentError) lambda { @securable.mode "444" }.should_not raise_error(ArgumentError) lambda { @securable.mode "7777" }.should_not raise_error(ArgumentError) lambda { @securable.mode "07777" }.should_not raise_error(ArgumentError) lambda { @securable.mode "-01" }.should raise_error(ArgumentError) lambda { @securable.mode "010000" }.should raise_error(ArgumentError) lambda { @securable.mode "-1" }.should raise_error(ArgumentError) lambda { @securable.mode "10000" }.should raise_error(ArgumentError) lambda { @securable.mode "07778" }.should raise_error(ArgumentError) lambda { @securable.mode "7778" }.should raise_error(ArgumentError) lambda { @securable.mode "4095" }.should raise_error(ArgumentError) lambda { @securable.mode "0foo1234" }.should raise_error(ArgumentError) lambda { @securable.mode "foo1234" }.should raise_error(ArgumentError) end it "should accept a unix file mode in numeric form as a ruby-interpreted integer" do lambda { @securable.mode 0 }.should_not raise_error(ArgumentError) lambda { @securable.mode 0000 }.should_not raise_error(ArgumentError) lambda { @securable.mode 444 }.should_not raise_error(ArgumentError) lambda { @securable.mode 0444 }.should_not raise_error(ArgumentError) lambda { @securable.mode 07777 }.should_not raise_error(ArgumentError) lambda { @securable.mode 292 }.should_not raise_error(ArgumentError) lambda { @securable.mode 4095 }.should_not raise_error(ArgumentError) lambda { @securable.mode 0111 }.should_not raise_error(ArgumentError) lambda { @securable.mode 73 }.should_not raise_error(ArgumentError) lambda { @securable.mode -01 }.should raise_error(ArgumentError) lambda { @securable.mode 010000 }.should raise_error(ArgumentError) lambda { @securable.mode -1 }.should raise_error(ArgumentError) lambda { @securable.mode 4096 }.should raise_error(ArgumentError) end end describe "windows-specific behavior" do before(:each) do platform_mock :windows do load File.join(File.dirname(__FILE__), "..", "..", "..", "lib", "chef", "config.rb") load File.join(File.dirname(__FILE__), "..", "..", "..", "lib", "chef", "mixin", "securable.rb") SECURABLE_CLASS = Class.new do include Chef::Mixin::Securable include Chef::Mixin::ParamsValidate end @securable = SECURABLE_CLASS.new end end it "should not accept a group name or id for group with spaces and multiple backslashes" do lambda { @securable.group 'test\ \group' }.should raise_error(ArgumentError) end it "should accept a unix file mode in string form as an octal number" do lambda { @securable.mode "0" }.should_not raise_error(ArgumentError) lambda { @securable.mode "0000" }.should_not raise_error(ArgumentError) lambda { @securable.mode "0111" }.should_not raise_error(ArgumentError) lambda { @securable.mode "0444" }.should_not raise_error(ArgumentError) lambda { @securable.mode "111" }.should_not raise_error(ArgumentError) lambda { @securable.mode "444" }.should_not raise_error(ArgumentError) lambda { @securable.mode "7777" }.should raise_error(ArgumentError) lambda { @securable.mode "07777" }.should raise_error(ArgumentError) lambda { @securable.mode "-01" }.should raise_error(ArgumentError) lambda { @securable.mode "010000" }.should raise_error(ArgumentError) lambda { @securable.mode "-1" }.should raise_error(ArgumentError) lambda { @securable.mode "10000" }.should raise_error(ArgumentError) lambda { @securable.mode "07778" }.should raise_error(ArgumentError) lambda { @securable.mode "7778" }.should raise_error(ArgumentError) lambda { @securable.mode "4095" }.should raise_error(ArgumentError) lambda { @securable.mode "0foo1234" }.should raise_error(ArgumentError) lambda { @securable.mode "foo1234" }.should raise_error(ArgumentError) end it "should accept a unix file mode in numeric form as a ruby-interpreted integer" do lambda { @securable.mode 0 }.should_not raise_error(ArgumentError) lambda { @securable.mode 0000 }.should_not raise_error(ArgumentError) lambda { @securable.mode 444 }.should_not raise_error(ArgumentError) lambda { @securable.mode 0444 }.should_not raise_error(ArgumentError) lambda { @securable.mode 07777 }.should raise_error(ArgumentError) lambda { @securable.mode 292 }.should_not raise_error(ArgumentError) lambda { @securable.mode 4095 }.should raise_error(ArgumentError) lambda { @securable.mode 0111 }.should_not raise_error(ArgumentError) lambda { @securable.mode 73 }.should_not raise_error(ArgumentError) lambda { @securable.mode -01 }.should raise_error(ArgumentError) lambda { @securable.mode 010000 }.should raise_error(ArgumentError) lambda { @securable.mode -1 }.should raise_error(ArgumentError) lambda { @securable.mode 4096 }.should raise_error(ArgumentError) end it "should allow you to specify :full_control, :modify, :read_execute, :read, and :write rights" do lambda { @securable.rights :full_control, "The Dude" }.should_not raise_error(ArgumentError) lambda { @securable.rights :modify, "The Dude" }.should_not raise_error(ArgumentError) lambda { @securable.rights :read_execute, "The Dude" }.should_not raise_error(ArgumentError) lambda { @securable.rights :read, "The Dude" }.should_not raise_error(ArgumentError) lambda { @securable.rights :write, "The Dude" }.should_not raise_error(ArgumentError) lambda { @securable.rights :to_party, "The Dude" }.should raise_error(ArgumentError) end it "should allow you to specify :full_control, :modify, :read_execute, :read, and :write deny_rights" do lambda { @securable.deny_rights :full_control, "The Dude" }.should_not raise_error(ArgumentError) lambda { @securable.deny_rights :modify, "The Dude" }.should_not raise_error(ArgumentError) lambda { @securable.deny_rights :read_execute, "The Dude" }.should_not raise_error(ArgumentError) lambda { @securable.deny_rights :read, "The Dude" }.should_not raise_error(ArgumentError) lambda { @securable.deny_rights :write, "The Dude" }.should_not raise_error(ArgumentError) lambda { @securable.deny_rights :to_party, "The Dude" }.should raise_error(ArgumentError) end it "should accept a principal as a string or an array" do lambda { @securable.rights :read, "The Dude" }.should_not raise_error(ArgumentError) lambda { @securable.rights :read, ["The Dude","Donny"] }.should_not raise_error(ArgumentError) lambda { @securable.rights :read, 3 }.should raise_error(ArgumentError) end it "should allow you to specify whether the permissions applies_to_children with true/false/:containers_only/:objects_only" do lambda { @securable.rights :read, "The Dude", :applies_to_children => false }.should_not raise_error(ArgumentError) lambda { @securable.rights :read, "The Dude", :applies_to_children => true }.should_not raise_error(ArgumentError) lambda { @securable.rights :read, "The Dude", :applies_to_children => :containers_only }.should_not raise_error(ArgumentError) lambda { @securable.rights :read, "The Dude", :applies_to_children => :objects_only }.should_not raise_error(ArgumentError) lambda { @securable.rights :read, "The Dude", :applies_to_children => 'poop' }.should raise_error(ArgumentError) end it "should allow you to specify whether the permissions applies_to_self with true/false" do lambda { @securable.rights :read, "The Dude", :applies_to_children => true, :applies_to_self => false }.should_not raise_error(ArgumentError) lambda { @securable.rights :read, "The Dude", :applies_to_self => true }.should_not raise_error(ArgumentError) lambda { @securable.rights :read, "The Dude", :applies_to_self => 'poop' }.should raise_error(ArgumentError) end it "should allow you to specify whether the permissions applies one_level_deep with true/false" do lambda { @securable.rights :read, "The Dude", :applies_to_children => true, :one_level_deep => false }.should_not raise_error(ArgumentError) lambda { @securable.rights :read, "The Dude", :applies_to_children => true, :one_level_deep => true }.should_not raise_error(ArgumentError) lambda { @securable.rights :read, "The Dude", :applies_to_children => true, :one_level_deep => 'poop' }.should raise_error(ArgumentError) end it "should allow multiple rights and deny_rights declarations" do @securable.rights :read, "The Dude" @securable.deny_rights :full_control, "The Dude" @securable.rights :full_control, "The Dude" @securable.rights :write, "The Dude" @securable.deny_rights :read, "The Dude" @securable.rights.size.should == 3 @securable.deny_rights.size.should == 2 end it "should allow you to specify whether the permission applies_to_self only if you specified applies_to_children" do lambda { @securable.rights :read, "The Dude", :applies_to_children => true, :applies_to_self => true }.should_not raise_error(ArgumentError) lambda { @securable.rights :read, "The Dude", :applies_to_children => true, :applies_to_self => false }.should_not raise_error(ArgumentError) lambda { @securable.rights :read, "The Dude", :applies_to_children => false, :applies_to_self => true }.should_not raise_error(ArgumentError) lambda { @securable.rights :read, "The Dude", :applies_to_children => false, :applies_to_self => false }.should raise_error(ArgumentError) lambda { @securable.rights :read, "The Dude", :applies_to_self => true }.should_not raise_error(ArgumentError) lambda { @securable.rights :read, "The Dude", :applies_to_self => false }.should_not raise_error(ArgumentError) end it "should allow you to specify whether the permission applies one_level_deep only if you specified applies_to_children" do lambda { @securable.rights :read, "The Dude", :applies_to_children => true, :one_level_deep => true }.should_not raise_error(ArgumentError) lambda { @securable.rights :read, "The Dude", :applies_to_children => true, :one_level_deep => false }.should_not raise_error(ArgumentError) lambda { @securable.rights :read, "The Dude", :applies_to_children => false, :one_level_deep => true }.should raise_error(ArgumentError) lambda { @securable.rights :read, "The Dude", :applies_to_children => false, :one_level_deep => false }.should_not raise_error(ArgumentError) lambda { @securable.rights :read, "The Dude", :one_level_deep => true }.should_not raise_error(ArgumentError) lambda { @securable.rights :read, "The Dude", :one_level_deep => false }.should_not raise_error(ArgumentError) end it "should allow you to specify whether the permissions inherit with true/false" do lambda { @securable.inherits true }.should_not raise_error(ArgumentError) lambda { @securable.inherits false }.should_not raise_error(ArgumentError) lambda { @securable.inherits "monkey" }.should raise_error(ArgumentError) end end end chef-11.8.2/spec/unit/mixin/deep_merge_spec.rb0000644000004100000410000003645712254362222021247 0ustar www-datawww-data# # Author:: Matthew Kent () # Author:: Steve Midgley (http://www.misuse.org/science) # Copyright:: Copyright (c) 2010 Matthew Kent # Copyright:: Copyright (c) 2008 Steve Midgley # License:: Apache License, Version 2.0 # # 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. # Notice: # This code is imported from deep_merge by Steve Midgley. deep_merge is # available under the MIT license from # http://trac.misuse.org/science/wiki/DeepMerge require 'spec_helper' # Test coverage from the original author converted to rspec describe Chef::Mixin::DeepMerge, "deep_merge!" do before do @dm = Chef::Mixin::DeepMerge @field_ko_prefix = '!merge' end # deep_merge core tests - moving from basic to more complex it "tests merging an hash w/array into blank hash" do hash_src = {'id' => '2'} hash_dst = {} @dm.deep_merge!(hash_src.dup, hash_dst) hash_dst.should == hash_src end it "tests merging an hash w/array into blank hash" do hash_src = {'region' => {'id' => ['227', '2']}} hash_dst = {} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == hash_src end it "tests merge from empty hash" do hash_src = {} hash_dst = {"property" => ["2","4"]} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"property" => ["2","4"]} end it "tests merge to empty hash" do hash_src = {"property" => ["2","4"]} hash_dst = {} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"property" => ["2","4"]} end it "tests simple string overwrite" do hash_src = {"name" => "value"} hash_dst = {"name" => "value1"} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"name" => "value"} end it "tests simple string overwrite of empty hash" do hash_src = {"name" => "value"} hash_dst = {} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == hash_src end it "tests hashes holding array" do hash_src = {"property" => ["1","3"]} hash_dst = {"property" => ["2","4"]} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"property" => ["2","4","1","3"]} end it "tests hashes holding hashes holding arrays (array with duplicate elements is merged with dest then src" do hash_src = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["1", "4+"]}} hash_dst = {"property" => {"bedroom_count" => ["3", "2"], "bathroom_count" => ["2"]}} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"property" => {"bedroom_count" => ["3","2","1"], "bathroom_count" => ["2", "1", "4+"]}} end it "tests hash holding hash holding array v string (string is overwritten by array)" do hash_src = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["1", "4+"]}} hash_dst = {"property" => {"bedroom_count" => "3", "bathroom_count" => ["2"]}} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2","1","4+"]}} end it "tests hash holding hash holding string v array (array is overwritten by string)" do hash_src = {"property" => {"bedroom_count" => "3", "bathroom_count" => ["1", "4+"]}} hash_dst = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2"]}} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"property" => {"bedroom_count" => "3", "bathroom_count" => ["2","1","4+"]}} end it "tests hash holding hash holding hash v array (array is overwritten by hash)" do hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["1", "4+"]}} hash_dst = {"property" => {"bedroom_count" => ["1", "2"], "bathroom_count" => ["2"]}} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["2","1","4+"]}} end it "tests 3 hash layers holding integers (integers are overwritten by source)" do hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["1", "4+"]}} hash_dst = {"property" => {"bedroom_count" => {"king_bed" => 2, "queen_bed" => 4}, "bathroom_count" => ["2"]}} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => 1}, "bathroom_count" => ["2","1","4+"]}} end it "tests 3 hash layers holding arrays of int (arrays are merged)" do hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => ["1", "4+"]}} hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4,1]}, "bathroom_count" => ["2","1","4+"]}} end it "tests 1 hash overwriting 3 hash layers holding arrays of int" do hash_src = {"property" => "1"} hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"property" => "1"} end it "tests 3 hash layers holding arrays of int (arrays are merged) but second hash's array is overwritten" do hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3], "queen_bed" => [1]}, "bathroom_count" => "1"}} hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4,1]}, "bathroom_count" => "1"}} end it "tests 3 hash layers holding arrays of int, but one holds int. This one overwrites, but the rest merge" do hash_src = {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => [1]}, "bathroom_count" => ["1"]}} hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => 3, "queen_bed" => [4,1]}, "bathroom_count" => ["2","1"]}} end it "tests 3 hash layers holding arrays of int, but source is incomplete." do hash_src = {"property" => {"bedroom_count" => {"king_bed" => [3]}, "bathroom_count" => ["1"]}} hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => [2,3], "queen_bed" => [4]}, "bathroom_count" => ["2","1"]}} end it "tests 3 hash layers holding arrays of int, but source is shorter and has new 2nd level ints." do hash_src = {"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}} hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"property" => {"bedroom_count" => {2=>3, "king_bed" => [2,3], "queen_bed" => [4]}, "bathroom_count" => ["2","1"]}} end it "tests 3 hash layers holding arrays of int, but source is empty" do hash_src = {} hash_dst = {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"property" => {"bedroom_count" => {"king_bed" => [2], "queen_bed" => [4]}, "bathroom_count" => ["2"]}} end it "tests 3 hash layers holding arrays of int, but dest is empty" do hash_src = {"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}} hash_dst = {} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"property" => {"bedroom_count" => {2=>3, "king_bed" => [3]}, "bathroom_count" => ["1"]}} end it "tests hash holding arrays of arrays" do hash_src = {["1", "2", "3"] => ["1", "2"]} hash_dst = {["4", "5"] => ["3"]} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {["1","2","3"] => ["1", "2"], ["4", "5"] => ["3"]} end it "tests merging of hash with blank hash, and make sure that source array split does not function when turned off" do hash_src = {'property' => {'bedroom_count' => ["1","2,3"]}} hash_dst = {} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {'property' => {'bedroom_count' => ["1","2,3"]}} end it "tests merging into a blank hash" do hash_src = {"action"=>"browse", "controller"=>"results"} hash_dst = {} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == hash_src end it "tests are unmerged hashes passed unmodified w/out :unpack_arrays?" do hash_src = {"amenity"=>{"id"=>["26,27"]}} hash_dst = {} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"amenity"=>{"id"=>["26,27"]}} end it "tests hash of array of hashes" do hash_src = {"item" => [{"1" => "3"}, {"2" => "4"}]} hash_dst = {"item" => [{"3" => "5"}]} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"item" => [{"3" => "5"}, {"1" => "3"}, {"2" => "4"}]} end # Additions since import it "should overwrite true with false when merging boolean values" do hash_src = {"valid" => false} hash_dst = {"valid" => true} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"valid" => false} end it "should overwrite false with true when merging boolean values" do hash_src = {"valid" => true} hash_dst = {"valid" => false} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"valid" => true} end it "should overwrite a string with an empty string when merging string values" do hash_src = {"item" => " "} hash_dst = {"item" => "orange"} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"item" => " "} end it "should overwrite an empty string with a string when merging string values" do hash_src = {"item" => "orange"} hash_dst = {"item" => " "} @dm.deep_merge!(hash_src, hash_dst) hash_dst.should == {"item" => "orange"} end end # deep_merge! # Chef specific describe Chef::Mixin::DeepMerge do before do @dm = Chef::Mixin::DeepMerge end describe "merge" do it "should merge a hash into an empty hash" do hash_dst = {} hash_src = {'id' => '2'} @dm.merge(hash_dst, hash_src).should == hash_src end it "should merge a nested hash into an empty hash" do hash_dst = {} hash_src = {'region' => {'id' => ['227', '2']}} @dm.merge(hash_dst, hash_src).should == hash_src end it "should overwrite as string value when merging hashes" do hash_dst = {"name" => "value1"} hash_src = {"name" => "value"} @dm.merge(hash_dst, hash_src).should == {"name" => "value"} end it "should merge arrays within hashes" do hash_dst = {"property" => ["2","4"]} hash_src = {"property" => ["1","3"]} @dm.merge(hash_dst, hash_src).should == {"property" => ["2","4","1","3"]} end it "should merge deeply nested hashes" do hash_dst = {"property" => {"values" => {"are" => "falling", "can" => "change"}}} hash_src = {"property" => {"values" => {"are" => "stable", "may" => "rise"}}} @dm.merge(hash_dst, hash_src).should == {"property" => {"values" => {"are" => "stable", "can" => "change", "may" => "rise"}}} end it "should not modify the source or destination during the merge" do hash_dst = {"property" => ["1","2","3"]} hash_src = {"property" => ["4","5","6"]} ret = @dm.merge(hash_dst, hash_src) hash_dst.should == {"property" => ["1","2","3"]} hash_src.should == {"property" => ["4","5","6"]} ret.should == {"property" => ["1","2","3","4","5","6"]} end end describe "role_merge" do it "errors out if knockout merge use is detected in an array" do hash_dst = {"property" => ["2","4"]} hash_src = {"property" => ["1","!merge:4"]} lambda {@dm.role_merge(hash_dst, hash_src)}.should raise_error(Chef::Mixin::DeepMerge::InvalidSubtractiveMerge) end it "errors out if knockout merge use is detected in an array (reversed merge order)" do hash_dst = {"property" => ["1","!merge:4"]} hash_src = {"property" => ["2","4"]} lambda {@dm.role_merge(hash_dst, hash_src)}.should raise_error(Chef::Mixin::DeepMerge::InvalidSubtractiveMerge) end it "errors out if knockout merge use is detected in a string" do hash_dst = {"property" => ["2","4"]} hash_src = {"property" => "!merge"} lambda {@dm.role_merge(hash_dst, hash_src)}.should raise_error(Chef::Mixin::DeepMerge::InvalidSubtractiveMerge) end it "errors out if knockout merge use is detected in a string (reversed merge order)" do hash_dst = {"property" => "!merge"} hash_src= {"property" => ["2","4"]} lambda {@dm.role_merge(hash_dst, hash_src)}.should raise_error(Chef::Mixin::DeepMerge::InvalidSubtractiveMerge) end end describe "hash-only merging" do it "merges Hashes like normal deep merge" do merge_ee_hash = {"top_level_a" => {"1_deep_a" => "1-a-merge-ee", "1_deep_b" => "1-deep-b-merge-ee"}, "top_level_b" => "top-level-b-merge-ee"} merge_with_hash = {"top_level_a" => {"1_deep_b" => "1-deep-b-merged-onto", "1_deep_c" => "1-deep-c-merged-onto"}, "top_level_b" => "top-level-b-merged-onto" } merged_result = @dm.hash_only_merge(merge_ee_hash, merge_with_hash) merged_result["top_level_b"].should == "top-level-b-merged-onto" merged_result["top_level_a"]["1_deep_a"].should == "1-a-merge-ee" merged_result["top_level_a"]["1_deep_b"].should == "1-deep-b-merged-onto" merged_result["top_level_a"]["1_deep_c"].should == "1-deep-c-merged-onto" end it "replaces arrays rather than merging them" do merge_ee_hash = {"top_level_a" => {"1_deep_a" => "1-a-merge-ee", "1_deep_b" => %w[A A A]}, "top_level_b" => "top-level-b-merge-ee"} merge_with_hash = {"top_level_a" => {"1_deep_b" => %w[B B B], "1_deep_c" => "1-deep-c-merged-onto"}, "top_level_b" => "top-level-b-merged-onto" } merged_result = @dm.hash_only_merge(merge_ee_hash, merge_with_hash) merged_result["top_level_b"].should == "top-level-b-merged-onto" merged_result["top_level_a"]["1_deep_a"].should == "1-a-merge-ee" merged_result["top_level_a"]["1_deep_b"].should == %w[B B B] end it "replaces non-hash items with hashes when there's a conflict" do merge_ee_hash = {"top_level_a" => "top-level-a-mergee", "top_level_b" => "top-level-b-merge-ee"} merge_with_hash = {"top_level_a" => {"1_deep_b" => %w[B B B], "1_deep_c" => "1-deep-c-merged-onto"}, "top_level_b" => "top-level-b-merged-onto" } merged_result = @dm.hash_only_merge(merge_ee_hash, merge_with_hash) merged_result["top_level_a"].should be_a(Hash) merged_result["top_level_a"]["1_deep_a"].should be_nil merged_result["top_level_a"]["1_deep_b"].should == %w[B B B] end end end chef-11.8.2/spec/unit/mixin/path_sanity_spec.rb0000644000004100000410000000572212254362222021465 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' class PathSanityTestHarness include Chef::Mixin::PathSanity end describe Chef::Mixin::PathSanity do before do @sanity = PathSanityTestHarness.new end describe "when enforcing path sanity" do before do Chef::Config[:enforce_path_sanity] = true @ruby_bindir = '/some/ruby/bin' @gem_bindir = '/some/gem/bin' Gem.stub!(:bindir).and_return(@gem_bindir) RbConfig::CONFIG.stub!(:[]).with('bindir').and_return(@ruby_bindir) Chef::Platform.stub!(:windows?).and_return(false) end it "adds all useful PATHs that are not yet in PATH to PATH" do env = {"PATH" => ""} @sanity.enforce_path_sanity(env) env["PATH"].should == "#{@ruby_bindir}:#{@gem_bindir}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" end it "does not re-add paths that already exist in PATH" do env = {"PATH" => "/usr/bin:/sbin:/bin"} @sanity.enforce_path_sanity(env) env["PATH"].should == "/usr/bin:/sbin:/bin:#{@ruby_bindir}:#{@gem_bindir}:/usr/local/sbin:/usr/local/bin:/usr/sbin" end it "adds the current executing Ruby's bindir and Gem bindir to the PATH" do env = {"PATH" => ""} @sanity.enforce_path_sanity(env) env["PATH"].should == "#{@ruby_bindir}:#{@gem_bindir}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" end it "does not create entries for Ruby/Gem bindirs if they exist in SANE_PATH or PATH" do ruby_bindir = '/usr/bin' gem_bindir = '/yo/gabba/gabba' Gem.stub!(:bindir).and_return(gem_bindir) RbConfig::CONFIG.stub!(:[]).with('bindir').and_return(ruby_bindir) env = {"PATH" => gem_bindir} @sanity.enforce_path_sanity(env) env["PATH"].should == "/yo/gabba/gabba:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" end it "builds a valid windows path" do ruby_bindir = 'C:\ruby\bin' gem_bindir = 'C:\gems\bin' Gem.stub!(:bindir).and_return(gem_bindir) RbConfig::CONFIG.stub!(:[]).with('bindir').and_return(ruby_bindir) Chef::Platform.stub!(:windows?).and_return(true) env = {"PATH" => 'C:\Windows\system32;C:\mr\softie'} @sanity.enforce_path_sanity(env) env["PATH"].should == "C:\\Windows\\system32;C:\\mr\\softie;#{ruby_bindir};#{gem_bindir}" end end end chef-11.8.2/spec/unit/mixin/command_spec.rb0000644000004100000410000000701612254362222020556 0ustar www-datawww-data# # Author:: Hongli Lai (hongli@phusion.nl) # Copyright:: Copyright (c) 2009 Phusion # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Mixin::Command, :volatile do if windows? pending("TODO MOVE: this is a platform specific integration test.") else describe "popen4" do include Chef::Mixin::Command it "should be possible to read the child process's stdout and stderr" do popen4("sh -c 'echo hello && echo world >&2'") do |pid, stdin, stdout, stderr| stdout.read.should == "hello\n" stderr.read.should == "world\n" end end it "should default all commands to be run in the POSIX standard C locale" do popen4("echo $LC_ALL") do |pid, stdin, stdout, stderr| stdout.read.strip.should == "C" end end it "should respect locale when specified explicitly" do popen4("echo $LC_ALL", :environment => {"LC_ALL" => "es"}) do |pid, stdin, stdout, stderr| stdout.read.strip.should == "es" end end it "should end when the child process reads from STDIN and a block is given" do lambda {Timeout.timeout(10) do popen4("ruby -e 'while gets; end'", :waitlast => true) do |pid, stdin, stdout, stderr| (1..5).each { |i| stdin.puts "#{i}" } end end }.should_not raise_error end describe "when a process detaches but doesn't close STDOUT and STDERR [CHEF-584]" do it "returns immediately after the first child process exits" do lambda {Timeout.timeout(10) do pid, stdin,stdout,stderr = nil,nil,nil,nil evil_forker="exit if fork; 10.times { sleep 1}" popen4("ruby -e '#{evil_forker}'") do |pid,stdin,stdout,stderr| end end}.should_not raise_error end end end describe "run_command" do include Chef::Mixin::Command it "logs the command's stderr and stdout output if the command failed" do Chef::Log.stub!(:level).and_return(:debug) begin run_command(:command => "sh -c 'echo hello; echo world >&2; false'") violated "Exception expected, but nothing raised." rescue => e e.message.should =~ /STDOUT: hello/ e.message.should =~ /STDERR: world/ end end describe "when a process detaches but doesn't close STDOUT and STDERR [CHEF-584]" do it "returns successfully" do # CHEF-2916 might have added a slight delay here, or our CI # infrastructure is burdened. Bumping timeout from 2 => 4 -- # btm # Serdar - During Solaris tests, we've seen that processes # are taking a long time to exit. Bumping timeout now to 10. lambda {Timeout.timeout(10) do evil_forker="exit if fork; 10.times { sleep 1}" run_command(:command => "ruby -e '#{evil_forker}'") end}.should_not raise_error end end end end end chef-11.8.2/spec/unit/mixin/xml_escape_spec.rb0000644000004100000410000000300412254362222021251 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' class XMLEscapingTestHarness include Chef::Mixin::XMLEscape end describe Chef::Mixin::XMLEscape do before do @escaper = XMLEscapingTestHarness.new end it "escapes ampersands to '&'" do @escaper.xml_escape("&").should == "&" end it "escapes angle brackets to < or >" do @escaper.xml_escape("<").should == "<" @escaper.xml_escape(">").should == ">" end it "does not modify ASCII strings" do @escaper.xml_escape('foobarbaz!@#$%^*()').should == 'foobarbaz!@#$%^*()' end it "converts invalid bytes to asterisks" do @escaper.xml_escape("\x00").should == "*" end it "converts UTF-8 correctly" do @escaper.xml_escape("\xC2\xA9").should == '©' end it "converts win 1252 characters correctly" do @escaper.xml_escape("\x80").should == '€' end end chef-11.8.2/spec/unit/mixin/convert_to_class_name_spec.rb0000644000004100000410000000327712254362222023514 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 Daniel DeLeo # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' class ConvertToClassTestHarness include Chef::Mixin::ConvertToClassName end describe Chef::Mixin::ConvertToClassName do before do @convert = ConvertToClassTestHarness.new end it "converts a_snake_case_word to a CamelCaseWord" do @convert.convert_to_class_name("now_camelized").should == "NowCamelized" end it "converts a CamelCaseWord to a snake_case_word" do @convert.convert_to_snake_case("NowImASnake").should == "now_im_a_snake" end it "removes the base classes before snake casing" do @convert.convert_to_snake_case("NameSpaced::Class::ThisIsWin", "NameSpaced::Class").should == "this_is_win" end it "removes the base classes without explicitly naming them and returns snake case" do @convert.snake_case_basename("NameSpaced::Class::ExtraWin").should == "extra_win" end it "interprets non-alphanumeric characters in snake case as word boundaries" do @convert.convert_to_class_name("now_camelized_without-hyphen").should == "NowCamelizedWithoutHyphen" end end chef-11.8.2/spec/unit/mixin/template_spec.rb0000644000004100000410000002344212254362222020754 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'cgi' describe Chef::Mixin::Template, "render_template" do let(:sep) { Chef::Platform.windows? ? "\r\n" : "\n" } before :each do @context = Chef::Mixin::Template::TemplateContext.new({}) end it "should render the template evaluated in the given context" do @context[:foo] = "bar" output = @context.render_template_from_string("<%= @foo %>") output.should == "bar" end template_contents = [ "Fancy\r\nTemplate\r\n\r\n", "Fancy\nTemplate\n\n", "Fancy\r\nTemplate\n\r\n"] describe "when running on windows" do before do Chef::Platform.stub!(:windows?).and_return(true) end it "should render the templates with windows line endings" do template_contents.each do |template_content| output = @context.render_template_from_string(template_content) output.each_line do |line| line.should end_with("\r\n") end end end end describe "when running on unix" do before do Chef::Platform.stub!(:windows?).and_return(false) end it "should render the templates with unix line endings" do template_contents.each do |template_content| output = @context.render_template_from_string(template_content) output.each_line do |line| line.should end_with("\n") end end end end it "should provide a node method to access @node" do @context[:node] = "tehShizzle" output = @context.render_template_from_string("<%= @node %>") output.should == "tehShizzle" end describe "with a template resource" do before :each do @cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, @cookbook_repo) } @node = Chef::Node.new cl = Chef::CookbookLoader.new(@cookbook_repo) cl.load_cookbooks @cookbook_collection = Chef::CookbookCollection.new(cl) @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) @rendered_file_location = Dir.tmpdir + '/openldap_stuff.conf' @resource = Chef::Resource::Template.new(@rendered_file_location) @resource.cookbook_name = 'openldap' @current_resource = @resource.dup @content_provider = Chef::Provider::Template::Content.new(@resource, @current_resource, @run_context) @template_context = Chef::Mixin::Template::TemplateContext.new({}) @template_context[:node] = @node @template_context[:template_finder] = Chef::Provider::TemplateFinder.new(@run_context, @resource.cookbook_name, @node) end it "should provide a render method" do output = @template_context.render_template_from_string("before {<%= render('test.erb').strip -%>} after") output.should == "before {We could be diving for pearls!} after" end it "should render local files" do begin tf = Tempfile.new("partial") tf.write "test" tf.rewind output = @template_context.render_template_from_string("before {<%= render '#{tf.path}', :local => true %>} after") output.should == "before {test} after" ensure tf.close end end it "should render partials from a different cookbook" do @template_context[:template_finder] = Chef::Provider::TemplateFinder.new(@run_context, 'apache2', @node) output = @template_context.render_template_from_string("before {<%= render('test.erb', :cookbook => 'openldap').strip %>} after") output.should == "before {We could be diving for pearls!} after" end it "should render using the source argument if provided" do begin tf = Tempfile.new("partial") tf.write "test" tf.rewind output = @template_context.render_template_from_string("before {<%= render 'something', :local => true, :source => '#{tf.path}' %>} after") output.should == "before {test} after" ensure tf.close end end it "should pass the node to partials" do @node.normal[:slappiness] = "happiness" output = @template_context.render_template_from_string("before {<%= render 'openldap_stuff.conf.erb' %>} after") output.should == "before {slappiness is happiness} after" end it "should pass the original variables to partials" do @template_context[:secret] = 'candy' output = @template_context.render_template_from_string("before {<%= render 'openldap_variable_stuff.conf.erb' %>} after") output == "before {super secret is candy} after" end it "should pass variables to partials" do output = @template_context.render_template_from_string("before {<%= render 'openldap_variable_stuff.conf.erb', :variables => {:secret => 'whatever' } %>} after") output.should == "before {super secret is whatever} after" end it "should pass variables to partials even if they are named the same" do @template_context[:secret] = 'one' output = @template_context.render_template_from_string("before {<%= render 'openldap_variable_stuff.conf.erb', :variables => {:secret => 'two' } %>} after <%= @secret %>") output.should == "before {super secret is two} after one" end it "should pass nil for missing variables in partials" do output = @template_context.render_template_from_string("before {<%= render 'openldap_variable_stuff.conf.erb', :variables => {} %>} after") output.should == "before {super secret is } after" output = @template_context.render_template_from_string("before {<%= render 'openldap_variable_stuff.conf.erb' %>} after") output.should == "before {super secret is } after" end it "should render nested partials" do path = File.expand_path(File.join(CHEF_SPEC_DATA, "partial_one.erb")) output = @template_context.render_template_from_string("before {<%= render('#{path}', :local => true).strip %>} after") output.should == "before {partial one We could be diving for pearls! calling home} after" end describe "when customizing the template context" do it "extends the context to include modules" do mod = Module.new do def hello "ohai" end end @template_context._extend_modules([mod]) output = @template_context.render_template_from_string("<%=hello%>") output.should == "ohai" end it "emits a warning when overriding 'core' methods" do mod = Module.new do def render end def node end def render_template end def render_template_from_string end end ['node', 'render', 'render_template', 'render_template_from_string'].each do |method_name| Chef::Log.should_receive(:warn).with(/^Core template method `#{method_name}' overridden by extension module/) end @template_context._extend_modules([mod]) end end end describe "when an exception is raised in the template" do def do_raise @context.render_template_from_string("foo\nbar\nbaz\n<%= this_is_not_defined %>\nquin\nqunx\ndunno") end it "should catch and re-raise the exception as a TemplateError" do lambda { do_raise }.should raise_error(Chef::Mixin::Template::TemplateError) end it "should raise an error if an attempt is made to access node but it is nil" do lambda {@context.render_template_from_string("<%= node %>") {|r| r}}.should raise_error(Chef::Mixin::Template::TemplateError) end describe "the raised TemplateError" do before :each do begin do_raise rescue Chef::Mixin::Template::TemplateError => e @exception = e end end it "should have the original exception" do @exception.original_exception.should be @exception.original_exception.message.should =~ /undefined local variable or method `this_is_not_defined'/ end it "should determine the line number of the exception" do @exception.line_number.should == 4 end it "should provide a source listing of the template around the exception" do @exception.source_listing.should == " 2: bar\n 3: baz\n 4: <%= this_is_not_defined %>\n 5: quin\n 6: qunx" end it "should provide the evaluation context of the template" do @exception.context.should == @context end it "should defer the message to the original exception" do @exception.message.should =~ /undefined local variable or method `this_is_not_defined'/ end it "should provide a nice source location" do @exception.source_location.should == "on line #4" end it "should create a pretty output for the terminal" do @exception.to_s.should =~ /Chef::Mixin::Template::TemplateError/ @exception.to_s.should =~ /undefined local variable or method `this_is_not_defined'/ @exception.to_s.should include(" 2: bar\n 3: baz\n 4: <%= this_is_not_defined %>\n 5: quin\n 6: qunx") @exception.to_s.should include(@exception.original_exception.backtrace.first) end end end end chef-11.8.2/spec/unit/chef_fs/0000755000004100000410000000000012254362222016046 5ustar www-datawww-datachef-11.8.2/spec/unit/chef_fs/file_pattern_spec.rb0000644000004100000410000005043112254362222022064 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/chef_fs/file_pattern' describe Chef::ChefFS::FilePattern do def p(str) Chef::ChefFS::FilePattern.new(str) end # Different kinds of patterns context 'with empty pattern ""' do let(:pattern) { Chef::ChefFS::FilePattern.new('') } it 'match?' do pattern.match?('').should be_true pattern.match?('/').should be_false pattern.match?('a').should be_false pattern.match?('a/b').should be_false end it 'exact_path' do pattern.exact_path.should == '' end it 'could_match_children?' do pattern.could_match_children?('').should be_false pattern.could_match_children?('a/b').should be_false end end context 'with root pattern "/"' do let(:pattern) { Chef::ChefFS::FilePattern.new('/') } it 'match?' do pattern.match?('/').should be_true pattern.match?('').should be_false pattern.match?('a').should be_false pattern.match?('/a').should be_false end it 'exact_path' do pattern.exact_path.should == '/' end it 'could_match_children?' do pattern.could_match_children?('').should be_false pattern.could_match_children?('/').should be_false pattern.could_match_children?('a').should be_false pattern.could_match_children?('a/b').should be_false pattern.could_match_children?('/a').should be_false end end context 'with simple pattern "abc"' do let(:pattern) { Chef::ChefFS::FilePattern.new('abc') } it 'match?' do pattern.match?('abc').should be_true pattern.match?('a').should be_false pattern.match?('abcd').should be_false pattern.match?('/abc').should be_false pattern.match?('').should be_false pattern.match?('/').should be_false end it 'exact_path' do pattern.exact_path.should == 'abc' end it 'could_match_children?' do pattern.could_match_children?('').should be_false pattern.could_match_children?('abc').should be_false pattern.could_match_children?('/abc').should be_false end end context 'with simple pattern "/abc"' do let(:pattern) { Chef::ChefFS::FilePattern.new('/abc') } it 'match?' do pattern.match?('/abc').should be_true pattern.match?('abc').should be_false pattern.match?('a').should be_false pattern.match?('abcd').should be_false pattern.match?('').should be_false pattern.match?('/').should be_false end it 'exact_path' do pattern.exact_path.should == '/abc' end it 'could_match_children?' do pattern.could_match_children?('abc').should be_false pattern.could_match_children?('/abc').should be_false pattern.could_match_children?('/').should be_true pattern.could_match_children?('').should be_false end it 'exact_child_name_under' do pattern.exact_child_name_under('/').should == 'abc' end end context 'with simple pattern "abc/def/ghi"' do let(:pattern) { Chef::ChefFS::FilePattern.new('abc/def/ghi') } it 'match?' do pattern.match?('abc/def/ghi').should be_true pattern.match?('/abc/def/ghi').should be_false pattern.match?('abc').should be_false pattern.match?('abc/def').should be_false end it 'exact_path' do pattern.exact_path.should == 'abc/def/ghi' end it 'could_match_children?' do pattern.could_match_children?('abc').should be_true pattern.could_match_children?('xyz').should be_false pattern.could_match_children?('/abc').should be_false pattern.could_match_children?('abc/def').should be_true pattern.could_match_children?('abc/xyz').should be_false pattern.could_match_children?('abc/def/ghi').should be_false end it 'exact_child_name_under' do pattern.exact_child_name_under('abc').should == 'def' pattern.exact_child_name_under('abc/def').should == 'ghi' end end context 'with simple pattern "/abc/def/ghi"' do let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/def/ghi') } it 'match?' do pattern.match?('/abc/def/ghi').should be_true pattern.match?('abc/def/ghi').should be_false pattern.match?('/abc').should be_false pattern.match?('/abc/def').should be_false end it 'exact_path' do pattern.exact_path.should == '/abc/def/ghi' end it 'could_match_children?' do pattern.could_match_children?('/abc').should be_true pattern.could_match_children?('/xyz').should be_false pattern.could_match_children?('abc').should be_false pattern.could_match_children?('/abc/def').should be_true pattern.could_match_children?('/abc/xyz').should be_false pattern.could_match_children?('/abc/def/ghi').should be_false end it 'exact_child_name_under' do pattern.exact_child_name_under('/').should == 'abc' pattern.exact_child_name_under('/abc').should == 'def' pattern.exact_child_name_under('/abc/def').should == 'ghi' end end context 'with simple pattern "a\*\b"', :pending => (Chef::Platform.windows?) do let(:pattern) { Chef::ChefFS::FilePattern.new('a\*\b') } it 'match?' do pattern.match?('a*b').should be_true pattern.match?('ab').should be_false pattern.match?('acb').should be_false pattern.match?('ab').should be_false end it 'exact_path' do pattern.exact_path.should == 'a*b' end it 'could_match_children?' do pattern.could_match_children?('a/*b').should be_false end end context 'with star pattern "/abc/*/ghi"' do let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/*/ghi') } it 'match?' do pattern.match?('/abc/def/ghi').should be_true pattern.match?('/abc/ghi').should be_false end it 'exact_path' do pattern.exact_path.should be_nil end it 'could_match_children?' do pattern.could_match_children?('/abc').should be_true pattern.could_match_children?('/xyz').should be_false pattern.could_match_children?('abc').should be_false pattern.could_match_children?('/abc/def').should be_true pattern.could_match_children?('/abc/xyz').should be_true pattern.could_match_children?('/abc/def/ghi').should be_false end it 'exact_child_name_under' do pattern.exact_child_name_under('/').should == 'abc' pattern.exact_child_name_under('/abc').should == nil pattern.exact_child_name_under('/abc/def').should == 'ghi' end end context 'with star pattern "/abc/d*f/ghi"' do let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/d*f/ghi') } it 'match?' do pattern.match?('/abc/def/ghi').should be_true pattern.match?('/abc/dxf/ghi').should be_true pattern.match?('/abc/df/ghi').should be_true pattern.match?('/abc/dxyzf/ghi').should be_true pattern.match?('/abc/d/ghi').should be_false pattern.match?('/abc/f/ghi').should be_false pattern.match?('/abc/ghi').should be_false pattern.match?('/abc/xyz/ghi').should be_false end it 'exact_path' do pattern.exact_path.should be_nil end it 'could_match_children?' do pattern.could_match_children?('/abc').should be_true pattern.could_match_children?('/xyz').should be_false pattern.could_match_children?('abc').should be_false pattern.could_match_children?('/abc/def').should be_true pattern.could_match_children?('/abc/xyz').should be_false pattern.could_match_children?('/abc/dxyzf').should be_true pattern.could_match_children?('/abc/df').should be_true pattern.could_match_children?('/abc/d').should be_false pattern.could_match_children?('/abc/f').should be_false pattern.could_match_children?('/abc/def/ghi').should be_false end it 'exact_child_name_under' do pattern.exact_child_name_under('/').should == 'abc' pattern.exact_child_name_under('/abc').should == nil pattern.exact_child_name_under('/abc/def').should == 'ghi' end end context 'with star pattern "/abc/d??f/ghi"' do let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/d??f/ghi') } it 'match?' do pattern.match?('/abc/deef/ghi').should be_true pattern.match?('/abc/deeef/ghi').should be_false pattern.match?('/abc/def/ghi').should be_false pattern.match?('/abc/df/ghi').should be_false pattern.match?('/abc/d/ghi').should be_false pattern.match?('/abc/f/ghi').should be_false pattern.match?('/abc/ghi').should be_false end it 'exact_path' do pattern.exact_path.should be_nil end it 'could_match_children?' do pattern.could_match_children?('/abc').should be_true pattern.could_match_children?('/xyz').should be_false pattern.could_match_children?('abc').should be_false pattern.could_match_children?('/abc/deef').should be_true pattern.could_match_children?('/abc/deeef').should be_false pattern.could_match_children?('/abc/def').should be_false pattern.could_match_children?('/abc/df').should be_false pattern.could_match_children?('/abc/d').should be_false pattern.could_match_children?('/abc/f').should be_false pattern.could_match_children?('/abc/deef/ghi').should be_false end it 'exact_child_name_under' do pattern.exact_child_name_under('/').should == 'abc' pattern.exact_child_name_under('/abc').should == nil pattern.exact_child_name_under('/abc/deef').should == 'ghi' end end context 'with star pattern "/abc/d[a-z][0-9]f/ghi"', :pending => (Chef::Platform.windows?) do let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/d[a-z][0-9]f/ghi') } it 'match?' do pattern.match?('/abc/de1f/ghi').should be_true pattern.match?('/abc/deef/ghi').should be_false pattern.match?('/abc/d11f/ghi').should be_false pattern.match?('/abc/de11f/ghi').should be_false pattern.match?('/abc/dee1f/ghi').should be_false pattern.match?('/abc/df/ghi').should be_false pattern.match?('/abc/d/ghi').should be_false pattern.match?('/abc/f/ghi').should be_false pattern.match?('/abc/ghi').should be_false end it 'exact_path' do pattern.exact_path.should be_nil end it 'could_match_children?' do pattern.could_match_children?('/abc').should be_true pattern.could_match_children?('/xyz').should be_false pattern.could_match_children?('abc').should be_false pattern.could_match_children?('/abc/de1f').should be_true pattern.could_match_children?('/abc/deef').should be_false pattern.could_match_children?('/abc/d11f').should be_false pattern.could_match_children?('/abc/de11f').should be_false pattern.could_match_children?('/abc/dee1f').should be_false pattern.could_match_children?('/abc/def').should be_false pattern.could_match_children?('/abc/df').should be_false pattern.could_match_children?('/abc/d').should be_false pattern.could_match_children?('/abc/f').should be_false pattern.could_match_children?('/abc/de1f/ghi').should be_false end it 'exact_child_name_under' do pattern.exact_child_name_under('/').should == 'abc' pattern.exact_child_name_under('/abc').should == nil pattern.exact_child_name_under('/abc/de1f').should == 'ghi' end end context 'with star pattern "/abc/**/ghi"' do let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/**/ghi') } it 'match?' do pattern.match?('/abc/def/ghi').should be_true pattern.match?('/abc/d/e/f/ghi').should be_true pattern.match?('/abc/ghi').should be_false pattern.match?('/abcdef/d/ghi').should be_false pattern.match?('/abc/d/defghi').should be_false pattern.match?('/xyz').should be_false end it 'exact_path' do pattern.exact_path.should be_nil end it 'could_match_children?' do pattern.could_match_children?('/abc').should be_true pattern.could_match_children?('/abc/d').should be_true pattern.could_match_children?('/abc/d/e').should be_true pattern.could_match_children?('/abc/d/e/f').should be_true pattern.could_match_children?('/abc/def/ghi').should be_true pattern.could_match_children?('abc').should be_false pattern.could_match_children?('/xyz').should be_false end it 'exact_child_name_under' do pattern.exact_child_name_under('/').should == 'abc' pattern.exact_child_name_under('/abc').should == nil pattern.exact_child_name_under('/abc/def').should == nil end end context 'with star pattern "/abc**/ghi"' do let(:pattern) { Chef::ChefFS::FilePattern.new('/abc**/ghi') } it 'match?' do pattern.match?('/abc/def/ghi').should be_true pattern.match?('/abc/d/e/f/ghi').should be_true pattern.match?('/abc/ghi').should be_true pattern.match?('/abcdef/ghi').should be_true pattern.match?('/abc/defghi').should be_false pattern.match?('/xyz').should be_false end it 'exact_path' do pattern.exact_path.should be_nil end it 'could_match_children?' do pattern.could_match_children?('/abc').should be_true pattern.could_match_children?('/abcdef').should be_true pattern.could_match_children?('/abc/d/e').should be_true pattern.could_match_children?('/abc/d/e/f').should be_true pattern.could_match_children?('/abc/def/ghi').should be_true pattern.could_match_children?('abc').should be_false end it 'could_match_children? /abc** returns false for /xyz' do pending 'Make could_match_children? more rigorous' do # At the moment, we return false for this, but in the end it would be nice to return true: pattern.could_match_children?('/xyz').should be_false end end it 'exact_child_name_under' do pattern.exact_child_name_under('/').should == nil pattern.exact_child_name_under('/abc').should == nil pattern.exact_child_name_under('/abc/def').should == nil end end context 'with star pattern "/abc/**ghi"' do let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/**ghi') } it 'match?' do pattern.match?('/abc/def/ghi').should be_true pattern.match?('/abc/def/ghi/ghi').should be_true pattern.match?('/abc/def/ghi/jkl').should be_false pattern.match?('/abc/d/e/f/ghi').should be_true pattern.match?('/abc/ghi').should be_true pattern.match?('/abcdef/ghi').should be_false pattern.match?('/abc/defghi').should be_true pattern.match?('/xyz').should be_false end it 'exact_path' do pattern.exact_path.should be_nil end it 'could_match_children?' do pattern.could_match_children?('/abc').should be_true pattern.could_match_children?('/abcdef').should be_false pattern.could_match_children?('/abc/d/e').should be_true pattern.could_match_children?('/abc/d/e/f').should be_true pattern.could_match_children?('/abc/def/ghi').should be_true pattern.could_match_children?('abc').should be_false pattern.could_match_children?('/xyz').should be_false end it 'exact_child_name_under' do pattern.exact_child_name_under('/').should == 'abc' pattern.exact_child_name_under('/abc').should == nil pattern.exact_child_name_under('/abc/def').should == nil end end context 'with star pattern "a**b**c"' do let(:pattern) { Chef::ChefFS::FilePattern.new('a**b**c') } it 'match?' do pattern.match?('axybzwc').should be_true pattern.match?('abc').should be_true pattern.match?('axyzwc').should be_false pattern.match?('ac').should be_false pattern.match?('a/x/y/b/z/w/c').should be_true end it 'exact_path' do pattern.exact_path.should be_nil end end context 'normalization tests' do it 'handles trailing slashes' do p('abc/').normalized_pattern.should == 'abc' p('abc/').exact_path.should == 'abc' p('abc/').match?('abc').should be_true p('//').normalized_pattern.should == '/' p('//').exact_path.should == '/' p('//').match?('/').should be_true p('/./').normalized_pattern.should == '/' p('/./').exact_path.should == '/' p('/./').match?('/').should be_true end it 'handles multiple slashes' do p('abc//def').normalized_pattern.should == 'abc/def' p('abc//def').exact_path.should == 'abc/def' p('abc//def').match?('abc/def').should be_true p('abc//').normalized_pattern.should == 'abc' p('abc//').exact_path.should == 'abc' p('abc//').match?('abc').should be_true end it 'handles dot' do p('abc/./def').normalized_pattern.should == 'abc/def' p('abc/./def').exact_path.should == 'abc/def' p('abc/./def').match?('abc/def').should be_true p('./abc/def').normalized_pattern.should == 'abc/def' p('./abc/def').exact_path.should == 'abc/def' p('./abc/def').match?('abc/def').should be_true p('/.').normalized_pattern.should == '/' p('/.').exact_path.should == '/' p('/.').match?('/').should be_true end it 'handles dot by itself', :pending => "decide what to do with dot by itself" do p('.').normalized_pattern.should == '.' p('.').exact_path.should == '.' p('.').match?('.').should be_true p('./').normalized_pattern.should == '.' p('./').exact_path.should == '.' p('./').match?('.').should be_true end it 'handles dotdot' do p('abc/../def').normalized_pattern.should == 'def' p('abc/../def').exact_path.should == 'def' p('abc/../def').match?('def').should be_true p('abc/def/../..').normalized_pattern.should == '' p('abc/def/../..').exact_path.should == '' p('abc/def/../..').match?('').should be_true p('/*/../def').normalized_pattern.should == '/def' p('/*/../def').exact_path.should == '/def' p('/*/../def').match?('/def').should be_true p('/*/*/../def').normalized_pattern.should == '/*/def' p('/*/*/../def').exact_path.should be_nil p('/*/*/../def').match?('/abc/def').should be_true p('/abc/def/../..').normalized_pattern.should == '/' p('/abc/def/../..').exact_path.should == '/' p('/abc/def/../..').match?('/').should be_true p('abc/../../def').normalized_pattern.should == '../def' p('abc/../../def').exact_path.should == '../def' p('abc/../../def').match?('../def').should be_true end it 'handles dotdot with double star' do p('abc**/def/../ghi').exact_path.should be_nil p('abc**/def/../ghi').match?('abc/ghi').should be_true p('abc**/def/../ghi').match?('abc/x/y/z/ghi').should be_true p('abc**/def/../ghi').match?('ghi').should be_false end it 'raises error on dotdot with overlapping double star' do lambda { Chef::ChefFS::FilePattern.new('abc/**/../def').exact_path }.should raise_error(ArgumentError) lambda { Chef::ChefFS::FilePattern.new('abc/**/abc/../../def').exact_path }.should raise_error(ArgumentError) end it 'handles leading dotdot' do p('../abc/def').exact_path.should == '../abc/def' p('../abc/def').match?('../abc/def').should be_true p('/../abc/def').exact_path.should == '/abc/def' p('/../abc/def').match?('/abc/def').should be_true p('..').exact_path.should == '..' p('..').match?('..').should be_true p('/..').exact_path.should == '/' p('/..').match?('/').should be_true end end # match? # - single element matches (empty, fixed, ?, *, characters, escapes) # - nested matches # - absolute matches # - trailing slashes # - ** # exact_path # - empty # - single element and nested matches, with escapes # - absolute and relative # - ?, *, characters, ** # could_match_children? # # # # context 'with pattern "abc"' do end context 'with pattern "/abc"' do end context 'with pattern "abc/def/ghi"' do end context 'with pattern "/abc/def/ghi"' do end # Exercise the different methods to their maximum end chef-11.8.2/spec/unit/chef_fs/file_system_spec.rb0000644000004100000410000000762012254362222021735 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/chef_fs/file_system' require 'chef/chef_fs/file_pattern' describe Chef::ChefFS::FileSystem do include FileSystemSupport context 'with empty filesystem' do let(:fs) { memory_fs('', {}) } context 'list' do it '/' do list_should_yield_paths(fs, '/', '/') end it '/a' do list_should_yield_paths(fs, '/a', '/a') end it '/a/b' do list_should_yield_paths(fs, '/a/b', '/a/b') end it '/*' do list_should_yield_paths(fs, '/*', '/') end end context 'resolve_path' do it '/' do Chef::ChefFS::FileSystem.resolve_path(fs, '/').path.should == '/' end it 'nonexistent /a' do Chef::ChefFS::FileSystem.resolve_path(fs, '/a').path.should == '/a' end it 'nonexistent /a/b' do Chef::ChefFS::FileSystem.resolve_path(fs, '/a/b').path.should == '/a/b' end end end context 'with a populated filesystem' do let(:fs) { memory_fs('', { :a => { :aa => { :c => '', :zz => '' }, :ab => { :c => '', } }, :x => '' }) } context 'list' do it '/**' do list_should_yield_paths(fs, '/**', '/', '/a', '/x', '/a/aa', '/a/aa/c', '/a/aa/zz', '/a/ab', '/a/ab/c') end it '/' do list_should_yield_paths(fs, '/', '/') end it '/*' do list_should_yield_paths(fs, '/*', '/', '/a', '/x') end it '/*/*' do list_should_yield_paths(fs, '/*/*', '/a/aa', '/a/ab') end it '/*/*/*' do list_should_yield_paths(fs, '/*/*/*', '/a/aa/c', '/a/aa/zz', '/a/ab/c') end it '/*/*/?' do list_should_yield_paths(fs, '/*/*/?', '/a/aa/c', '/a/ab/c') end it '/a/*/c' do list_should_yield_paths(fs, '/a/*/c', '/a/aa/c', '/a/ab/c') end it '/**b/c' do list_should_yield_paths(fs, '/**b/c', '/a/ab/c') end it '/a/ab/c' do no_blocking_calls_allowed list_should_yield_paths(fs, '/a/ab/c', '/a/ab/c') end it 'nonexistent /a/ab/blah' do no_blocking_calls_allowed list_should_yield_paths(fs, '/a/ab/blah', '/a/ab/blah') end it 'nonexistent /a/ab/blah/bjork' do no_blocking_calls_allowed list_should_yield_paths(fs, '/a/ab/blah/bjork', '/a/ab/blah/bjork') end end context 'resolve_path' do before(:each) do no_blocking_calls_allowed end it 'resolves /' do Chef::ChefFS::FileSystem.resolve_path(fs, '/').path.should == '/' end it 'resolves /x' do Chef::ChefFS::FileSystem.resolve_path(fs, '/x').path.should == '/x' end it 'resolves /a' do Chef::ChefFS::FileSystem.resolve_path(fs, '/a').path.should == '/a' end it 'resolves /a/aa' do Chef::ChefFS::FileSystem.resolve_path(fs, '/a/aa').path.should == '/a/aa' end it 'resolves /a/aa/zz' do Chef::ChefFS::FileSystem.resolve_path(fs, '/a/aa/zz').path.should == '/a/aa/zz' end it 'resolves nonexistent /y/x/w' do Chef::ChefFS::FileSystem.resolve_path(fs, '/y/x/w').path.should == '/y/x/w' end end end end chef-11.8.2/spec/unit/chef_fs/diff_spec.rb0000644000004100000410000002721212254362222020321 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/chef_fs/file_pattern' require 'chef/chef_fs/command_line' # Removes the date stamp from the diff and replaces it with ' DATE' # example match: "/dev/null\t2012-10-16 16:15:54.000000000 +0000" # windows match: "--- /dev/null\tTue Oct 16 18:04:34 2012" def remove_os_differences(diff) diff = diff.gsub(/([+-]{3}.*)\t.*/, '\1 DATE') diff.gsub(/^@@ -\d(,\d)? \+\d(,\d)? @@/, 'CONTEXT_LINE_NUMBERS') end describe 'diff', :uses_diff => true do include FileSystemSupport context 'with two filesystems with all types of difference' do let(:a) { memory_fs('a', { :both_dirs => { :sub_both_dirs => { :subsub => nil }, :sub_both_files => nil, :sub_both_files_different => "a\n", :sub_both_dirs_empty => {}, :sub_dirs_empty_in_a_filled_in_b => {}, :sub_dirs_empty_in_b_filled_in_a => { :subsub => nil }, :sub_a_only_dir => { :subsub => nil }, :sub_a_only_file => nil, :sub_dir_in_a_file_in_b => {}, :sub_file_in_a_dir_in_b => nil }, :both_files => nil, :both_files_different => "a\n", :both_dirs_empty => {}, :dirs_empty_in_a_filled_in_b => {}, :dirs_empty_in_b_filled_in_a => { :subsub => nil }, :dirs_in_a_cannot_be_in_b => {}, :file_in_a_cannot_be_in_b => nil, :a_only_dir => { :subsub => nil }, :a_only_file => nil, :dir_in_a_file_in_b => {}, :file_in_a_dir_in_b => nil }, /cannot_be_in_a/) } let(:b) { memory_fs('b', { :both_dirs => { :sub_both_dirs => { :subsub => nil }, :sub_both_files => nil, :sub_both_files_different => "b\n", :sub_both_dirs_empty => {}, :sub_dirs_empty_in_a_filled_in_b => { :subsub => nil }, :sub_dirs_empty_in_b_filled_in_a => {}, :sub_b_only_dir => { :subsub => nil }, :sub_b_only_file => nil, :sub_dir_in_a_file_in_b => nil, :sub_file_in_a_dir_in_b => {} }, :both_files => nil, :both_files_different => "b\n", :both_dirs_empty => {}, :dirs_empty_in_a_filled_in_b => { :subsub => nil }, :dirs_empty_in_b_filled_in_a => {}, :dirs_in_b_cannot_be_in_a => {}, :file_in_b_cannot_be_in_a => nil, :b_only_dir => { :subsub => nil }, :b_only_file => nil, :dir_in_a_file_in_b => nil, :file_in_a_dir_in_b => {} }, /cannot_be_in_b/) } it 'Chef::ChefFS::CommandLine.diff_print(/)' do results = [] Chef::ChefFS::CommandLine.diff_print(pattern('/'), a, b, nil, nil) do |diff| results << remove_os_differences(diff) end results.should =~ [ 'diff --knife a/both_dirs/sub_both_files_different b/both_dirs/sub_both_files_different --- a/both_dirs/sub_both_files_different DATE +++ b/both_dirs/sub_both_files_different DATE CONTEXT_LINE_NUMBERS -a +b ','diff --knife a/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub b/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub new file --- /dev/null DATE +++ b/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub DATE CONTEXT_LINE_NUMBERS +subsub ','diff --knife a/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub b/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub deleted file --- a/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub DATE +++ /dev/null DATE CONTEXT_LINE_NUMBERS -subsub ','Only in a/both_dirs: sub_a_only_dir ','diff --knife a/both_dirs/sub_a_only_file b/both_dirs/sub_a_only_file deleted file --- a/both_dirs/sub_a_only_file DATE +++ /dev/null DATE CONTEXT_LINE_NUMBERS -sub_a_only_file ','File a/both_dirs/sub_dir_in_a_file_in_b is a directory while file b/both_dirs/sub_dir_in_a_file_in_b is a regular file ','File a/both_dirs/sub_file_in_a_dir_in_b is a regular file while file b/both_dirs/sub_file_in_a_dir_in_b is a directory ','Only in b/both_dirs: sub_b_only_dir ','diff --knife a/both_dirs/sub_b_only_file b/both_dirs/sub_b_only_file new file --- /dev/null DATE +++ b/both_dirs/sub_b_only_file DATE CONTEXT_LINE_NUMBERS +sub_b_only_file ','diff --knife a/both_files_different b/both_files_different --- a/both_files_different DATE +++ b/both_files_different DATE CONTEXT_LINE_NUMBERS -a +b ','diff --knife a/dirs_empty_in_a_filled_in_b/subsub b/dirs_empty_in_a_filled_in_b/subsub new file --- /dev/null DATE +++ b/dirs_empty_in_a_filled_in_b/subsub DATE CONTEXT_LINE_NUMBERS +subsub ','diff --knife a/dirs_empty_in_b_filled_in_a/subsub b/dirs_empty_in_b_filled_in_a/subsub deleted file --- a/dirs_empty_in_b_filled_in_a/subsub DATE +++ /dev/null DATE CONTEXT_LINE_NUMBERS -subsub ','Only in a: a_only_dir ','diff --knife a/a_only_file b/a_only_file deleted file --- a/a_only_file DATE +++ /dev/null DATE CONTEXT_LINE_NUMBERS -a_only_file ','File a/dir_in_a_file_in_b is a directory while file b/dir_in_a_file_in_b is a regular file ','File a/file_in_a_dir_in_b is a regular file while file b/file_in_a_dir_in_b is a directory ','Only in b: b_only_dir ','diff --knife a/b_only_file b/b_only_file new file --- /dev/null DATE +++ b/b_only_file DATE CONTEXT_LINE_NUMBERS +b_only_file ' ] end it 'Chef::ChefFS::CommandLine.diff_print(/both_dirs)' do results = [] Chef::ChefFS::CommandLine.diff_print(pattern('/both_dirs'), a, b, nil, nil) do |diff| results << remove_os_differences(diff) end results.should =~ [ 'diff --knife a/both_dirs/sub_both_files_different b/both_dirs/sub_both_files_different --- a/both_dirs/sub_both_files_different DATE +++ b/both_dirs/sub_both_files_different DATE CONTEXT_LINE_NUMBERS -a +b ','diff --knife a/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub b/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub new file --- /dev/null DATE +++ b/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub DATE CONTEXT_LINE_NUMBERS +subsub ','diff --knife a/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub b/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub deleted file --- a/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub DATE +++ /dev/null DATE CONTEXT_LINE_NUMBERS -subsub ','Only in a/both_dirs: sub_a_only_dir ','diff --knife a/both_dirs/sub_a_only_file b/both_dirs/sub_a_only_file deleted file --- a/both_dirs/sub_a_only_file DATE +++ /dev/null DATE CONTEXT_LINE_NUMBERS -sub_a_only_file ','File a/both_dirs/sub_dir_in_a_file_in_b is a directory while file b/both_dirs/sub_dir_in_a_file_in_b is a regular file ','File a/both_dirs/sub_file_in_a_dir_in_b is a regular file while file b/both_dirs/sub_file_in_a_dir_in_b is a directory ','Only in b/both_dirs: sub_b_only_dir ','diff --knife a/both_dirs/sub_b_only_file b/both_dirs/sub_b_only_file new file --- /dev/null DATE +++ b/both_dirs/sub_b_only_file DATE CONTEXT_LINE_NUMBERS +sub_b_only_file ' ] end it 'Chef::ChefFS::CommandLine.diff_print(/) with depth 1' do results = [] Chef::ChefFS::CommandLine.diff_print(pattern('/'), a, b, 1, nil) do |diff| results << remove_os_differences(diff) end results.should =~ [ 'Common subdirectories: b/both_dirs ','diff --knife a/both_files_different b/both_files_different --- a/both_files_different DATE +++ b/both_files_different DATE CONTEXT_LINE_NUMBERS -a +b ','Common subdirectories: b/both_dirs_empty ','Common subdirectories: b/dirs_empty_in_b_filled_in_a ','Common subdirectories: b/dirs_empty_in_a_filled_in_b ','Only in a: a_only_dir ','diff --knife a/a_only_file b/a_only_file deleted file --- a/a_only_file DATE +++ /dev/null DATE CONTEXT_LINE_NUMBERS -a_only_file ','File a/dir_in_a_file_in_b is a directory while file b/dir_in_a_file_in_b is a regular file ','File a/file_in_a_dir_in_b is a regular file while file b/file_in_a_dir_in_b is a directory ','Only in b: b_only_dir ','diff --knife a/b_only_file b/b_only_file new file --- /dev/null DATE +++ b/b_only_file DATE CONTEXT_LINE_NUMBERS +b_only_file ' ] end it 'Chef::ChefFS::CommandLine.diff_print(/*_*) with depth 0' do results = [] Chef::ChefFS::CommandLine.diff_print(pattern('/*_*'), a, b, 0, nil) do |diff| results << remove_os_differences(diff) end results.should =~ [ 'Common subdirectories: b/both_dirs ','diff --knife a/both_files_different b/both_files_different --- a/both_files_different DATE +++ b/both_files_different DATE CONTEXT_LINE_NUMBERS -a +b ','Common subdirectories: b/both_dirs_empty ','Common subdirectories: b/dirs_empty_in_b_filled_in_a ','Common subdirectories: b/dirs_empty_in_a_filled_in_b ','Only in a: a_only_dir ','diff --knife a/a_only_file b/a_only_file deleted file --- a/a_only_file DATE +++ /dev/null DATE CONTEXT_LINE_NUMBERS -a_only_file ','File a/dir_in_a_file_in_b is a directory while file b/dir_in_a_file_in_b is a regular file ','File a/file_in_a_dir_in_b is a regular file while file b/file_in_a_dir_in_b is a directory ','Only in b: b_only_dir ','diff --knife a/b_only_file b/b_only_file new file --- /dev/null DATE +++ b/b_only_file DATE CONTEXT_LINE_NUMBERS +b_only_file ' ] end it 'Chef::ChefFS::CommandLine.diff_print(/) in name-only mode' do results = [] Chef::ChefFS::CommandLine.diff_print(pattern('/'), a, b, nil, :name_only) do |diff| results << remove_os_differences(diff) end results.should =~ [ "b/both_dirs/sub_both_files_different\n", "b/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub\n", "b/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub\n", "b/both_dirs/sub_a_only_dir\n", "b/both_dirs/sub_a_only_file\n", "b/both_dirs/sub_b_only_dir\n", "b/both_dirs/sub_b_only_file\n", "b/both_dirs/sub_dir_in_a_file_in_b\n", "b/both_dirs/sub_file_in_a_dir_in_b\n", "b/both_files_different\n", "b/dirs_empty_in_b_filled_in_a/subsub\n", "b/dirs_empty_in_a_filled_in_b/subsub\n", "b/a_only_dir\n", "b/a_only_file\n", "b/b_only_dir\n", "b/b_only_file\n", "b/dir_in_a_file_in_b\n", "b/file_in_a_dir_in_b\n" ] end it 'Chef::ChefFS::CommandLine.diff_print(/) in name-status mode' do results = [] Chef::ChefFS::CommandLine.diff_print(pattern('/'), a, b, nil, :name_status) do |diff| results << remove_os_differences(diff) end results.should =~ [ "M\tb/both_dirs/sub_both_files_different\n", "D\tb/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub\n", "A\tb/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub\n", "D\tb/both_dirs/sub_a_only_dir\n", "D\tb/both_dirs/sub_a_only_file\n", "A\tb/both_dirs/sub_b_only_dir\n", "A\tb/both_dirs/sub_b_only_file\n", "T\tb/both_dirs/sub_dir_in_a_file_in_b\n", "T\tb/both_dirs/sub_file_in_a_dir_in_b\n", "M\tb/both_files_different\n", "D\tb/dirs_empty_in_b_filled_in_a/subsub\n", "A\tb/dirs_empty_in_a_filled_in_b/subsub\n", "D\tb/a_only_dir\n", "D\tb/a_only_file\n", "A\tb/b_only_dir\n", "A\tb/b_only_file\n", "T\tb/dir_in_a_file_in_b\n", "T\tb/file_in_a_dir_in_b\n" ] end end end chef-11.8.2/spec/unit/chef_fs/file_system/0000755000004100000410000000000012254362222020371 5ustar www-datawww-datachef-11.8.2/spec/unit/chef_fs/file_system/operation_failed_error_spec.rb0000644000004100000410000000356612254362222026457 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/chef_fs/file_system/operation_failed_error' describe Chef::ChefFS::FileSystem::OperationFailedError do context 'message' do let(:error_message) { 'HTTP error writing: 400 "Bad Request"' } context 'has a cause attribute and HTTP result code is 400' do it 'include error cause' do allow_message_expectations_on_nil response_body = '{"error":["Invalid key test in request body"]}' @response.stub(:code).and_return("400") @response.stub(:body).and_return(response_body) exception = Net::HTTPServerException.new("(exception) unauthorized", @response) proc { raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, exception), error_message }.should raise_error(Chef::ChefFS::FileSystem::OperationFailedError, "#{error_message} cause: #{response_body}") end end context 'does not have a cause attribute' do it 'does not include error cause' do proc { raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self), error_message }.should raise_error(Chef::ChefFS::FileSystem::OperationFailedError, error_message) end end end end chef-11.8.2/spec/unit/run_context_spec.rb0000644000004100000410000001063112254362222020361 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tim Hinderliter () # Author:: Christopher Walters () # Copyright:: Copyright (c) 2008, 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'support/lib/library_load_order' Chef::Log.level = :debug describe Chef::RunContext do before(:each) do @chef_repo_path = File.expand_path(File.join(CHEF_SPEC_DATA, "run_context", "cookbooks")) cl = Chef::CookbookLoader.new(@chef_repo_path) cl.load_cookbooks @cookbook_collection = Chef::CookbookCollection.new(cl) @node = Chef::Node.new @node.run_list << "test" << "test::one" << "test::two" @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) end it "has a cookbook collection" do @run_context.cookbook_collection.should == @cookbook_collection end it "has a node" do @run_context.node.should == @node end describe "loading cookbooks for a run list" do before do @run_context.load(@node.run_list.expand('_default')) end it "should load all the definitions in the cookbooks for this node" do @run_context.definitions.should have_key(:new_cat) @run_context.definitions.should have_key(:new_badger) @run_context.definitions.should have_key(:new_dog) end it "should load all the recipes specified for this node" do @run_context.resource_collection[0].to_s.should == "cat[einstein]" @run_context.resource_collection[1].to_s.should == "cat[loulou]" @run_context.resource_collection[2].to_s.should == "cat[birthday]" @run_context.resource_collection[3].to_s.should == "cat[peanut]" @run_context.resource_collection[4].to_s.should == "cat[fat peanut]" end it "loads all the attribute files in the cookbook collection" do @run_context.loaded_fully_qualified_attribute?("test", "george").should be_true @node[:george].should == "washington" end it "registers attributes files as loaded so they won't be reloaded" do # This test unfortunately is pretty tightly intertwined with the # implementation of how nodes load attribute files, but is the only # convenient way to test this behavior. @node.should_not_receive(:from_file) @node.include_attribute("test::george") end end describe "querying the contents of cookbooks" do before do @chef_repo_path = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) cl = Chef::CookbookLoader.new(@chef_repo_path) cl.load_cookbooks @cookbook_collection = Chef::CookbookCollection.new(cl) @node = Chef::Node.new @node.set[:platform] = "ubuntu" @node.set[:platform_version] = "13.04" @node.name("testing") @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) end it "queries whether a given cookbook has a specific template" do @run_context.should have_template_in_cookbook("openldap", "test.erb") @run_context.should_not have_template_in_cookbook("openldap", "missing.erb") end it "errors when querying for a template in a not-available cookbook" do expect do @run_context.has_template_in_cookbook?("no-such-cookbook", "foo.erb") end.to raise_error(Chef::Exceptions::CookbookNotFound) end it "queries whether a given cookbook has a specific cookbook_file" do @run_context.should have_cookbook_file_in_cookbook("java", "java.response") @run_context.should_not have_cookbook_file_in_cookbook("java", "missing.txt") end it "errors when querying for a cookbook_file in a not-available cookbook" do expect do @run_context.has_cookbook_file_in_cookbook?("no-such-cookbook", "foo.txt") end.to raise_error(Chef::Exceptions::CookbookNotFound) end end end chef-11.8.2/spec/unit/platform_spec.rb0000644000004100000410000002030412254362222017633 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe "Chef::Platform supports" do [ :mac_os_x, :mac_os_x_server, :freebsd, :ubuntu, :debian, :centos, :fedora, :suse, :opensuse, :redhat, :oracle, :gentoo, :arch, :solaris, :mswin, :mingw32, :windows, :gcel ].each do |platform| it "#{platform}" do Chef::Platform.platforms.should have_key(platform) end end end describe Chef::Platform do before :all do @original_platform_map = Chef::Platform.platforms end after :all do || Chef::Platform.platforms = @original_platform_map end before(:each) do Chef::Platform.platforms = { :darwin => { ">= 10.11" => { :file => "new_darwinian" }, "9.2.2" => { :file => "darwinian", :else => "thing" }, :default => { :file => "old school", :snicker => "snack" } }, :mars_volta => { }, :default => { :file => Chef::Provider::File, :pax => "brittania", :cat => "nice" } } @events = Chef::EventDispatch::Dispatcher.new end it "should allow you to look up a platform by name and version, returning the provider map for it" do pmap = Chef::Platform.find("Darwin", "9.2.2") pmap.should be_a_kind_of(Hash) pmap[:file].should eql("darwinian") end it "should allow you to look up a platform by name and version using \"greater than\" style operators" do pmap = Chef::Platform.find("Darwin", "11.1.0") pmap.should be_a_kind_of(Hash) pmap[:file].should eql("new_darwinian") end it "should use the default providers for an os if the specific version does not exist" do pmap = Chef::Platform.find("Darwin", "1") pmap.should be_a_kind_of(Hash) pmap[:file].should eql("old school") end it "should use the default providers if the os doesn't give me a default, but does exist" do pmap = Chef::Platform.find("mars_volta", "1") pmap.should be_a_kind_of(Hash) pmap[:file].should eql(Chef::Provider::File) end it "should use the default provider if the os does not exist" do pmap = Chef::Platform.find("AIX", "1") pmap.should be_a_kind_of(Hash) pmap[:file].should eql(Chef::Provider::File) end it "should merge the defaults for an os with the specific version" do pmap = Chef::Platform.find("Darwin", "9.2.2") pmap[:file].should eql("darwinian") pmap[:snicker].should eql("snack") end it "should merge the defaults for an os with the universal defaults" do pmap = Chef::Platform.find("Darwin", "9.2.2") pmap[:file].should eql("darwinian") pmap[:pax].should eql("brittania") end it "should allow you to look up a provider for a platform directly by symbol" do Chef::Platform.find_provider("Darwin", "9.2.2", :file).should eql("darwinian") end it "should raise an exception if a provider cannot be found for a resource type" do lambda { Chef::Platform.find_provider("Darwin", "9.2.2", :coffee) }.should raise_error(ArgumentError) end it "should look up a provider for a resource with a Chef::Resource object" do kitty = Chef::Resource::Cat.new("loulou") Chef::Platform.find_provider("Darwin", "9.2.2", kitty).should eql("nice") end it "should look up a provider with a node and a Chef::Resource object" do kitty = Chef::Resource::Cat.new("loulou") node = Chef::Node.new node.name("Intel") node.automatic_attrs[:platform] = "mac_os_x" node.automatic_attrs[:platform_version] = "9.2.2" Chef::Platform.find_provider_for_node(node, kitty).should eql("nice") end it "should not throw an exception when the platform version has an unknown format" do Chef::Platform.find_provider(:darwin, "bad-version", :file).should eql("old school") end it "should prefer an explicit provider" do kitty = Chef::Resource::Cat.new("loulou") kitty.stub!(:provider).and_return(Chef::Provider::File) node = Chef::Node.new node.name("Intel") node.automatic_attrs[:platform] = "mac_os_x" node.automatic_attrs[:platform_version] = "9.2.2" Chef::Platform.find_provider_for_node(node, kitty).should eql(Chef::Provider::File) end it "should look up a provider based on the resource name if nothing else matches" do kitty = Chef::Resource::Cat.new("loulou") class Chef::Provider::Cat < Chef::Provider; end Chef::Platform.platforms[:default].delete(:cat) node = Chef::Node.new node.name("Intel") node.automatic_attrs[:platform] = "mac_os_x" node.automatic_attrs[:platform_version] = "8.5" Chef::Platform.find_provider_for_node(node, kitty).should eql(Chef::Provider::Cat) end def setup_file_resource node = Chef::Node.new node.automatic_attrs[:platform] = "mac_os_x" node.automatic_attrs[:platform_version] = "9.2.2" run_context = Chef::RunContext.new(node, {}, @events) [ Chef::Resource::File.new("whateva", run_context), run_context ] end it "returns a provider object given a Chef::Resource object which has a valid run context and an action" do file, run_context = setup_file_resource provider = Chef::Platform.provider_for_resource(file, :foo) provider.should be_an_instance_of(Chef::Provider::File) provider.new_resource.should equal(file) provider.run_context.should equal(run_context) end it "returns a provider object given a Chef::Resource object which has a valid run context without an action" do file, run_context = setup_file_resource provider = Chef::Platform.provider_for_resource(file) provider.should be_an_instance_of(Chef::Provider::File) provider.new_resource.should equal(file) provider.run_context.should equal(run_context) end it "raises an error when trying to find the provider for a resource with no run context" do file = Chef::Resource::File.new("whateva") lambda {Chef::Platform.provider_for_resource(file)}.should raise_error(ArgumentError) end it "does not support finding a provider by resource and node -- a run context is required" do lambda {Chef::Platform.provider_for_node('node', 'resource')}.should raise_error(NotImplementedError) end it "should update the provider map with map" do Chef::Platform.set( :platform => :darwin, :version => "9.2.2", :resource => :file, :provider => "masterful" ) Chef::Platform.platforms[:darwin]["9.2.2"][:file].should eql("masterful") Chef::Platform.set( :platform => :darwin, :resource => :file, :provider => "masterful" ) Chef::Platform.platforms[:darwin][:default][:file].should eql("masterful") Chef::Platform.set( :resource => :file, :provider => "masterful" ) Chef::Platform.platforms[:default][:file].should eql("masterful") Chef::Platform.set( :platform => :hero, :version => "9.2.2", :resource => :file, :provider => "masterful" ) Chef::Platform.platforms[:hero]["9.2.2"][:file].should eql("masterful") Chef::Platform.set( :resource => :file, :provider => "masterful" ) Chef::Platform.platforms[:default][:file].should eql("masterful") Chef::Platform.platforms = {} Chef::Platform.set( :resource => :file, :provider => "masterful" ) Chef::Platform.platforms[:default][:file].should eql("masterful") Chef::Platform.platforms = { :neurosis => {} } Chef::Platform.set(:platform => :neurosis, :resource => :package, :provider => "masterful") Chef::Platform.platforms[:neurosis][:default][:package].should eql("masterful") end end chef-11.8.2/spec/unit/data_bag_item_spec.rb0000644000004100000410000002164312254362222020556 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/data_bag_item' describe Chef::DataBagItem do before(:each) do @data_bag_item = Chef::DataBagItem.new end describe "initialize" do it "should be a Chef::DataBagItem" do @data_bag_item.should be_a_kind_of(Chef::DataBagItem) end end describe "data_bag" do it "should let you set the data_bag to a string" do @data_bag_item.data_bag("clowns").should == "clowns" end it "should return the current data_bag type" do @data_bag_item.data_bag "clowns" @data_bag_item.data_bag.should == "clowns" end it "should not accept spaces" do lambda { @data_bag_item.data_bag "clown masters" }.should raise_error(ArgumentError) end it "should throw an ArgumentError if you feed it anything but a string" do lambda { @data_bag_item.data_bag Hash.new }.should raise_error(ArgumentError) end end describe "raw_data" do it "should let you set the raw_data with a hash" do lambda { @data_bag_item.raw_data = { "id" => "octahedron" } }.should_not raise_error end it "should let you set the raw_data from a mash" do lambda { @data_bag_item.raw_data = Mash.new({ "id" => "octahedron" }) }.should_not raise_error end it "should raise an exception if you set the raw data without a key" do lambda { @data_bag_item.raw_data = { "monkey" => "pants" } }.should raise_error(ArgumentError) end it "should raise an exception if you set the raw data to something other than a hash" do lambda { @data_bag_item.raw_data = "katie rules" }.should raise_error(ArgumentError) end it "should accept alphanum/-/_ for the id" do lambda { @data_bag_item.raw_data = { "id" => "h1-_" } }.should_not raise_error(ArgumentError) end it "should raise an exception if the id contains anything but alphanum/-/_" do lambda { @data_bag_item.raw_data = { "id" => "!@#" } }.should raise_error(ArgumentError) end it "should return the raw data" do @data_bag_item.raw_data = { "id" => "highway_of_emptiness" } @data_bag_item.raw_data.should == { "id" => "highway_of_emptiness" } end it "should be a Mash by default" do @data_bag_item.raw_data.should be_a_kind_of(Mash) end end describe "object_name" do before(:each) do @data_bag_item.data_bag("dreams") @data_bag_item.raw_data = { "id" => "the_beatdown" } end it "should return an object name based on the bag name and the raw_data id" do @data_bag_item.object_name.should == "data_bag_item_dreams_the_beatdown" end end describe "class method object_name" do it "should return an object name based based on the bag name and an id" do Chef::DataBagItem.object_name("zen", "master").should == "data_bag_item_zen_master" end end describe "when used like a Hash" do before(:each) do @data_bag_item.raw_data = { "id" => "journey", "trials" => "been through" } end it "responds to keys" do @data_bag_item.keys.should include("id") @data_bag_item.keys.should include("trials") end it "supports element reference with []" do @data_bag_item["id"].should == "journey" end it "implements all the methods of Hash" do methods = [:rehash, :to_hash, :[], :fetch, :[]=, :store, :default, :default=, :default_proc, :index, :size, :length, :empty?, :each_value, :each_key, :each_pair, :each, :keys, :values, :values_at, :delete, :delete_if, :reject!, :clear, :invert, :update, :replace, :merge!, :merge, :has_key?, :has_value?, :key?, :value?] methods.each do |m| @data_bag_item.should respond_to(m) end end end describe "to_hash" do before(:each) do @data_bag_item.data_bag("still_lost") @data_bag_item.raw_data = { "id" => "whoa", "i_know" => "kung_fu" } @to_hash = @data_bag_item.to_hash end it "should return a hash" do @to_hash.should be_a_kind_of(Hash) end it "should have the raw_data keys as top level keys" do @to_hash["id"].should == "whoa" @to_hash["i_know"].should == "kung_fu" end it "should have the chef_type of data_bag_item" do @to_hash["chef_type"].should == "data_bag_item" end it "should have the data_bag set" do @to_hash["data_bag"].should == "still_lost" end end describe "when deserializing from JSON" do before(:each) do @data_bag_item.data_bag('mars_volta') @data_bag_item.raw_data = { "id" => "octahedron", "snooze" => { "finally" => :world_will }} @deserial = Chef::JSONCompat.from_json(@data_bag_item.to_json) end it "should deserialize to a Chef::DataBagItem object" do @deserial.should be_a_kind_of(Chef::DataBagItem) end it "should have a matching 'data_bag' value" do @deserial.data_bag.should == @data_bag_item.data_bag end it "should have a matching 'id' key" do @deserial["id"].should == "octahedron" end it "should have a matching 'snooze' key" do @deserial["snooze"].should == { "finally" => "world_will" } end end describe "when converting to a string" do it "converts to a string in the form data_bag_item[ID]" do @data_bag_item['id'] = "heart of darkness" @data_bag_item.to_s.should == 'data_bag_item[heart of darkness]' end it "inspects as data_bag_item[BAG, ID, RAW_DATA]" do raw_data = {"id" => "heart_of_darkness", "author" => "Conrad"} @data_bag_item.raw_data = raw_data @data_bag_item.data_bag("books") @data_bag_item.inspect.should == "data_bag_item[\"books\", \"heart_of_darkness\", #{raw_data.inspect}]" end end describe "save" do before do @rest = mock("Chef::REST") Chef::REST.stub!(:new).and_return(@rest) @data_bag_item['id'] = "heart of darkness" raw_data = {"id" => "heart_of_darkness", "author" => "Conrad"} @data_bag_item.raw_data = raw_data @data_bag_item.data_bag("books") end it "should update the item when it already exists" do @rest.should_receive(:put_rest).with("data/books/heart_of_darkness", @data_bag_item) @data_bag_item.save end it "should create if the item is not found" do exception = mock("404 error", :code => "404") @rest.should_receive(:put_rest).and_raise(Net::HTTPServerException.new("foo", exception)) @rest.should_receive(:post_rest).with("data/books", @data_bag_item) @data_bag_item.save end describe "when whyrun mode is enabled" do before do Chef::Config[:why_run] = true end after do Chef::Config[:why_run] = false end it "should not save" do @rest.should_not_receive(:put_rest) @rest.should_not_receive(:post_rest) @data_bag_item.data_bag("books") @data_bag_item.save end end end describe "when loading" do before do @data_bag_item.raw_data = {"id" => "charlie", "shell" => "zsh", "ssh_keys" => %w{key1 key2}} @data_bag_item.data_bag("users") end describe "from an API call" do before do @http_client = mock("Chef::REST") Chef::REST.stub!(:new).and_return(@http_client) end it "converts raw data to a data bag item" do @http_client.should_receive(:get_rest).with("data/users/charlie").and_return(@data_bag_item.to_hash) item = Chef::DataBagItem.load(:users, "charlie") item.should be_a_kind_of(Chef::DataBagItem) item.should == @data_bag_item end it "does not convert when a DataBagItem is returned from the API call" do @http_client.should_receive(:get_rest).with("data/users/charlie").and_return(@data_bag_item) item = Chef::DataBagItem.load(:users, "charlie") item.should be_a_kind_of(Chef::DataBagItem) item.should equal(@data_bag_item) end end describe "in solo mode" do before do Chef::Config[:solo] = true end after do Chef::Config[:solo] = false end it "converts the raw data to a data bag item" do Chef::DataBag.should_receive(:load).with('users').and_return({'charlie' => @data_bag_item.to_hash}) item = Chef::DataBagItem.load('users', 'charlie') item.should be_a_kind_of(Chef::DataBagItem) item.should == @data_bag_item end end end end chef-11.8.2/spec/unit/shell_out_spec.rb0000644000004100000410000000142412254362222020007 0ustar www-datawww-datarequire File.expand_path('../../spec_helper', __FILE__) describe "Chef::ShellOut deprecation notices" do it "logs a warning when initializing a new Chef::ShellOut object" do Chef::Log.should_receive(:warn).with("Chef::ShellOut is deprecated, please use Mixlib::ShellOut") Chef::Log.should_receive(:warn).with(/Called from\:/) Chef::ShellOut.new("pwd") end end describe "Chef::Exceptions::ShellCommandFailed deprecation notices" do it "logs a warning when referencing the constant Chef::Exceptions::ShellCommandFailed" do Chef::Log.should_receive(:warn).with("Chef::Exceptions::ShellCommandFailed is deprecated, use Mixlib::ShellOut::ShellCommandFailed") Chef::Log.should_receive(:warn).with(/Called from\:/) Chef::Exceptions::ShellCommandFailed end end chef-11.8.2/spec/unit/rest_spec.rb0000644000004100000410000006526412254362222017002 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Brown () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'uri' require 'net/https' require 'stringio' SIGNING_KEY_DOT_PEM="-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA49TA0y81ps0zxkOpmf5V4/c4IeR5yVyQFpX3JpxO4TquwnRh 8VSUhrw8kkTLmB3cS39Db+3HadvhoqCEbqPE6915kXSuk/cWIcNozujLK7tkuPEy YVsyTioQAddSdfe+8EhQVf3oHxaKmUd6waXrWqYCnhxgOjxocenREYNhZ/OETIei PbOku47vB4nJK/0GhKBytL2XnsRgfKgDxf42BqAi1jglIdeq8lAWZNF9TbNBU21A O1iuT7Pm6LyQujhggPznR5FJhXKRUARXBJZawxpGV4dGtdcahwXNE4601aXPra+x PcRd2puCNoEDBzgVuTSsLYeKBDMSfs173W1QYwIDAQABAoIBAGF05q7vqOGbMaSD 2Q7YbuE/JTHKTBZIlBI1QC2x+0P5GDxyEFttNMOVzcs7xmNhkpRw8eX1LrInrpMk WsIBKAFFEfWYlf0RWtRChJjNl+szE9jQxB5FJnWtJH/FHa78tR6PsF24aQyzVcJP g0FGujBihwgfV0JSCNOBkz8MliQihjQA2i8PGGmo4R4RVzGfxYKTIq9vvRq/+QEa Q4lpVLoBqnENpnY/9PTl6JMMjW2b0spbLjOPVwDaIzXJ0dChjNXo15K5SHI5mALJ I5gN7ODGb8PKUf4619ez194FXq+eob5YJdilTFKensIUvt3YhP1ilGMM+Chi5Vi/ /RCTw3ECgYEA9jTw4wv9pCswZ9wbzTaBj9yZS3YXspGg26y6Ohq3ZmvHz4jlT6uR xK+DDcUiK4072gci8S4Np0fIVS7q6ivqcOdzXPrTF5/j+MufS32UrBbUTPiM1yoO ECcy+1szl/KoLEV09bghPbvC58PFSXV71evkaTETYnA/F6RK12lEepcCgYEA7OSy bsMrGDVU/MKJtwqyGP9ubA53BorM4Pp9VVVSCrGGVhb9G/XNsjO5wJC8J30QAo4A s59ZzCpyNRy046AB8jwRQuSwEQbejSdeNgQGXhZ7aIVUtuDeFFdaIz/zjVgxsfj4 DPOuzieMmJ2MLR4F71ocboxNoDI7xruPSE8dDhUCgYA3vx732cQxgtHwAkeNPJUz dLiE/JU7CnxIoSB9fYUfPLI+THnXgzp7NV5QJN2qzMzLfigsQcg3oyo6F2h7Yzwv GkjlualIRRzCPaCw4Btkp7qkPvbs1QngIHALt8fD1N69P3DPHkTwjG4COjKWgnJq qoHKS6Fe/ZlbigikI6KsuwKBgQCTlSLoyGRHr6oj0hqz01EDK9ciMJzMkZp0Kvn8 OKxlBxYW+jlzut4MQBdgNYtS2qInxUoAnaz2+hauqhSzntK3k955GznpUatCqx0R b857vWviwPX2/P6+E3GPdl8IVsKXCvGWOBZWTuNTjQtwbDzsUepWoMgXnlQJSn5I YSlLxQKBgQD16Gw9kajpKlzsPa6XoQeGmZALT6aKWJQlrKtUQIrsIWM0Z6eFtX12 2jjHZ0awuCQ4ldqwl8IfRogWMBkHOXjTPVK0YKWWlxMpD/5+bGPARa5fir8O1Zpo Y6S6MeZ69Rp89ma4ttMZ+kwi1+XyHqC/dlcVRW42Zl5Dc7BALRlJjQ== -----END RSA PRIVATE KEY-----" describe Chef::REST do before(:each) do @log_stringio = StringIO.new Chef::Log.init(@log_stringio) Chef::REST::CookieJar.stub(:instance).and_return({}) @base_url = "http://chef.example.com:4000" @monkey_uri = URI.parse("http://chef.example.com:4000/monkey") @rest = Chef::REST.new(@base_url, nil, nil) Chef::REST::CookieJar.instance.clear end describe "calling an HTTP verb on a path or absolute URL" do it "adds a relative URL to the base url it was initialized with" do @rest.create_url("foo/bar/baz").should == URI.parse(@base_url + "/foo/bar/baz") end it "replaces the base URL when given an absolute URL" do @rest.create_url("http://chef-rulez.example.com:9000").should == URI.parse("http://chef-rulez.example.com:9000") end it "makes a :GET request with the composed url object" do @rest.should_receive(:send_http_request). with(:GET, @monkey_uri, STANDARD_READ_HEADERS, false). and_return([1,2,3]) @rest.should_receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3]) @rest.should_receive('success_response?'.to_sym).with(1).and_return(true) @rest.get_rest("monkey") end it "makes a :GET reqest for a streaming download with the composed url" do @rest.should_receive(:streaming_request).with('monkey', {}) @rest.get_rest("monkey", true) end STANDARD_READ_HEADERS = {"Accept"=>"application/json", "Accept"=>"application/json", "Accept-Encoding"=>"gzip;q=1.0,deflate;q=0.6,identity;q=0.3"} STANDARD_WRITE_HEADERS = {"Accept"=>"application/json", "Content-Type"=>"application/json", "Accept"=>"application/json", "Accept-Encoding"=>"gzip;q=1.0,deflate;q=0.6,identity;q=0.3"} it "makes a :DELETE request with the composed url object" do @rest.should_receive(:send_http_request). with(:DELETE, @monkey_uri, STANDARD_READ_HEADERS, false). and_return([1,2,3]) @rest.should_receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3]) @rest.should_receive('success_response?'.to_sym).with(1).and_return(true) @rest.delete_rest("monkey") end it "makes a :POST request with the composed url object and data" do @rest.should_receive(:send_http_request). with(:POST, @monkey_uri, STANDARD_WRITE_HEADERS, "\"data\""). and_return([1,2,3]) @rest.should_receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3]) @rest.should_receive('success_response?'.to_sym).with(1).and_return(true) @rest.post_rest("monkey", "data") end it "makes a :PUT request with the composed url object and data" do @rest.should_receive(:send_http_request). with(:PUT, @monkey_uri, STANDARD_WRITE_HEADERS, "\"data\""). and_return([1,2,3]) @rest.should_receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3]) @rest.should_receive('success_response?'.to_sym).with(1).and_return(true) @rest.put_rest("monkey", "data") end end describe "legacy API" do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem" @rest = Chef::REST.new(@base_url) end it 'responds to raw_http_request as a public method' do @rest.public_methods.map(&:to_s).should include("raw_http_request") end it 'calls the authn middleware' do data = "\"secure data\"" auth_headers = STANDARD_WRITE_HEADERS.merge({"auth_done"=>"yep"}) @rest.authenticator.should_receive(:handle_request). with(:POST, @monkey_uri, STANDARD_WRITE_HEADERS, data). and_return([:POST, @monkey_uri, auth_headers, data]) @rest.should_receive(:send_http_request). with(:POST, @monkey_uri, auth_headers, data). and_return([1,2,3]) @rest.should_receive('success_response?'.to_sym).with(1).and_return(true) @rest.raw_http_request(:POST, @monkey_uri, STANDARD_WRITE_HEADERS, data) end it 'sets correct authn headers' do data = "\"secure data\"" method, uri, auth_headers, d = @rest.authenticator.handle_request(:POST, @monkey_uri, STANDARD_WRITE_HEADERS, data) @rest.should_receive(:send_http_request). with(:POST, @monkey_uri, auth_headers, data). and_return([1,2,3]) @rest.should_receive('success_response?'.to_sym).with(1).and_return(true) @rest.raw_http_request(:POST, @monkey_uri, STANDARD_WRITE_HEADERS, data) end end describe "when configured to authenticate to the Chef server" do before do @url = URI.parse("http://chef.example.com:4000") Chef::Config[:node_name] = "webmonkey.example.com" Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem" @rest = Chef::REST.new(@url) end it "configures itself to use the node_name and client_key in the config by default" do @rest.client_name.should == "webmonkey.example.com" @rest.signing_key_filename.should == CHEF_SPEC_DATA + "/ssl/private_key.pem" end it "provides access to the raw key data" do @rest.signing_key.should == SIGNING_KEY_DOT_PEM end it "does not error out when initialized without credentials" do @rest = Chef::REST.new(@url, nil, nil) #should_not raise_error hides the bt from you, so screw it. @rest.client_name.should be_nil @rest.signing_key.should be_nil end it "indicates that requests should not be signed when it has no credentials" do @rest = Chef::REST.new(@url, nil, nil) @rest.sign_requests?.should be_false end it "raises PrivateKeyMissing when the key file doesn't exist" do lambda {Chef::REST.new(@url, "client-name", "/dev/null/nothing_here")}.should raise_error(Chef::Exceptions::PrivateKeyMissing) end it "raises InvalidPrivateKey when the key file doesnt' look like a key" do invalid_key_file = CHEF_SPEC_DATA + "/bad-config.rb" lambda {Chef::REST.new(@url, "client-name", invalid_key_file)}.should raise_error(Chef::Exceptions::InvalidPrivateKey) end it "can take private key as a sting :raw_key in options during initializaton" do Chef::REST.new(@url, "client-name", nil, :raw_key => SIGNING_KEY_DOT_PEM).signing_key.should == SIGNING_KEY_DOT_PEM end it "raises InvalidPrivateKey when the key passed as string :raw_key in options doesnt' look like a key" do lambda {Chef::REST.new(@url, "client-name", nil, :raw_key => "bad key string")}.should raise_error(Chef::Exceptions::InvalidPrivateKey) end end context "when making REST requests" do before(:each) do Chef::Config[:ssl_client_cert] = nil Chef::Config[:ssl_client_key] = nil @url = URI.parse("https://one:80/?foo=bar") @http_response = Net::HTTPSuccess.new("1.1", "200", "successful rest req") @http_response.stub(:read_body) @http_response.stub(:body).and_return("ninja") @http_response.add_field("Content-Length", "5") @http_client = Net::HTTP.new(@url.host, @url.port) Net::HTTP.stub(:new).and_return(@http_client) @http_client.stub(:request).and_yield(@http_response).and_return(@http_response) @base_headers = { 'Accept' => 'application/json', 'X-Chef-Version' => Chef::VERSION, 'Accept-Encoding' => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE} @req_with_body_headers = @base_headers.merge("Content-Type" => "application/json", "Content-Length" => '13') end describe "streaming downloads to a tempfile" do before do @tempfile = StringIO.new @tempfile.stub(:close!) @tempfile.stub(:path).and_return("/a-temporary-file") Tempfile.stub(:new).with("chef-rest").and_return(@tempfile) Tempfile.stub(:open).and_return(@tempfile) @request_mock = {} Net::HTTP::Get.stub(:new).and_return(@request_mock) end it "should build a new HTTP GET request without the application/json accept header" do expected_headers = {'Accept' => "*/*", 'X-Chef-Version' => Chef::VERSION, 'Accept-Encoding' => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE} Net::HTTP::Get.should_receive(:new).with("/?foo=bar", expected_headers).and_return(@request_mock) @rest.streaming_request(@url, {}) end it "should create a tempfile for the output of a raw request" do @rest.streaming_request(@url, {}).should equal(@tempfile) end it "should read the body of the response in chunks on a raw request" do @http_response.should_receive(:read_body).and_return(true) @rest.streaming_request(@url, {}) end it "should populate the tempfile with the value of the raw request" do @http_response.should_receive(:read_body).and_yield("ninja") @rest.streaming_request(@url, {}) #@tempfile.string.should include("ninja") end it "should close the tempfile if we're doing a raw request" do @tempfile.should_receive(:close).once.and_return(true) @rest.streaming_request(@url, {}) end it "should not raise a divide by zero exception if the size is 0" do @http_response.stub(:header).and_return({ 'Content-Length' => "5" }) @http_response.stub(:read_body).and_yield('') lambda { @rest.streaming_request(@url, {}) }.should_not raise_error end it "should not raise a divide by zero exception if the Content-Length is 0" do @http_response.stub(:header).and_return({ 'Content-Length' => "0" }) @http_response.stub(:read_body).and_yield("ninja") lambda { @rest.streaming_request(@url, {}) }.should_not raise_error end end describe "as JSON API requests" do before do @request_mock = {} Net::HTTP::Get.stub(:new).and_return(@request_mock) @base_headers = {"Accept" => "application/json", "X-Chef-Version" => Chef::VERSION, "Accept-Encoding" => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE } end it "should always include the X-Chef-Version header" do Net::HTTP::Get.should_receive(:new).with("/?foo=bar", @base_headers).and_return(@request_mock) @rest.request(:GET, @url, {}) end it "sets the user agent to chef-client" do # must reset to default b/c knife changes the UA Chef::REST::RESTRequest.user_agent = Chef::REST::RESTRequest::DEFAULT_UA @rest.request(:GET, @url, {}) @request_mock['User-Agent'].should match(/^Chef Client\/#{Chef::VERSION}/) end # CHEF-3140 context "when configured to disable compression" do before do @rest = Chef::REST.new(@base_url, nil, nil, :disable_gzip => true) end it "does not accept encoding gzip" do @rest.send(:build_headers, :GET, @url, {}).should_not have_key("Accept-Encoding") end it "does not decompress a response encoded as gzip" do @http_response.add_field("content-encoding", "gzip") request = Net::HTTP::Get.new(@url.path) Net::HTTP::Get.should_receive(:new).and_return(request) # will raise a Zlib error if incorrect @rest.request(:GET, @url, {}).should == "ninja" end end context "when configured with custom http headers" do before(:each) do @custom_headers = { 'X-Custom-ChefSecret' => 'sharpknives', 'X-Custom-RequestPriority' => 'extremely low' } Chef::Config[:custom_http_headers] = @custom_headers end after(:each) do Chef::Config[:custom_http_headers] = nil end it "should set them on the http request" do url_string = an_instance_of(String) header_hash = hash_including(@custom_headers) Net::HTTP::Get.should_receive(:new).with(url_string, header_hash) @rest.request(:GET, @url, {}) end end it "should set the cookie for this request if one exists for the given host:port" do Chef::REST::CookieJar.instance["#{@url.host}:#{@url.port}"] = "cookie monster" Net::HTTP::Get.should_receive(:new).with("/?foo=bar", @base_headers.merge('Cookie' => "cookie monster")).and_return(@request_mock) @rest.request(:GET, @url, {}) end it "should build a new HTTP GET request" do Net::HTTP::Get.should_receive(:new).with("/?foo=bar", @base_headers).and_return(@request_mock) @rest.request(:GET, @url, {}) end it "should build a new HTTP POST request" do request = Net::HTTP::Post.new(@url.path) expected_headers = @base_headers.merge("Content-Type" => 'application/json', 'Content-Length' => '13') Net::HTTP::Post.should_receive(:new).with("/?foo=bar", expected_headers).and_return(request) @rest.request(:POST, @url, {}, {:one=>:two}) request.body.should == '{"one":"two"}' end it "should build a new HTTP PUT request" do request = Net::HTTP::Put.new(@url.path) expected_headers = @base_headers.merge("Content-Type" => 'application/json', 'Content-Length' => '13') Net::HTTP::Put.should_receive(:new).with("/?foo=bar",expected_headers).and_return(request) @rest.request(:PUT, @url, {}, {:one=>:two}) request.body.should == '{"one":"two"}' end it "should build a new HTTP DELETE request" do Net::HTTP::Delete.should_receive(:new).with("/?foo=bar", @base_headers).and_return(@request_mock) @rest.request(:DELETE, @url) end it "should raise an error if the method is not GET/PUT/POST/DELETE" do lambda { @rest.request(:MONKEY, @url) }.should raise_error(ArgumentError) end it "returns nil when the response is successful but content-type is not JSON" do @rest.request(:GET, @url).should == "ninja" end it "should inflate the body as to an object if JSON is returned" do @http_response.add_field('content-type', "application/json") @http_response.stub(:body).and_return('{"ohai2u":"json_api"}') @rest.request(:GET, @url, {}).should == {"ohai2u"=>"json_api"} end %w[ HTTPFound HTTPMovedPermanently HTTPSeeOther HTTPUseProxy HTTPTemporaryRedirect HTTPMultipleChoice ].each do |resp_name| it "should call request again on a #{resp_name} response" do resp_cls = Net.const_get(resp_name) resp_code = Net::HTTPResponse::CODE_TO_OBJ.keys.detect { |k| Net::HTTPResponse::CODE_TO_OBJ[k] == resp_cls } http_response = Net::HTTPFound.new("1.1", resp_code, "bob is somewhere else again") http_response.add_field("location", @url.path) http_response.stub(:read_body) @http_client.stub(:request).and_yield(http_response).and_return(http_response) lambda { @rest.request(:GET, @url) }.should raise_error(Chef::Exceptions::RedirectLimitExceeded) [:PUT, :POST, :DELETE].each do |method| lambda { @rest.request(method, @url) }.should raise_error(Chef::Exceptions::InvalidRedirect) end end end it "should return `false` when response is 304 NotModified" do http_response = Net::HTTPNotModified.new("1.1", "304", "it's the same as when you asked 5 minutes ago") http_response.stub(:read_body) @http_client.stub(:request).and_yield(http_response).and_return(http_response) @rest.request(:GET, @url).should be_false end describe "when the request fails" do before do @original_log_level = Chef::Log.level Chef::Log.level = :info end after do Chef::Log.level = @original_log_level end it "should show the JSON error message on an unsuccessful request" do http_response = Net::HTTPServerError.new("1.1", "500", "drooling from inside of mouth") http_response.add_field("content-type", "application/json") http_response.stub(:body).and_return('{ "error":[ "Ears get sore!", "Not even four" ] }') http_response.stub(:read_body) @rest.stub(:sleep) @http_client.stub(:request).and_yield(http_response).and_return(http_response) lambda {@rest.request(:GET, @url)}.should raise_error(Net::HTTPFatalError) @log_stringio.string.should match(Regexp.escape('INFO: HTTP Request Returned 500 drooling from inside of mouth: Ears get sore!, Not even four')) end it "decompresses the JSON error message on an unsuccessful request" do http_response = Net::HTTPServerError.new("1.1", "500", "drooling from inside of mouth") http_response.add_field("content-type", "application/json") http_response.add_field("content-encoding", "deflate") unzipped_body = '{ "error":[ "Ears get sore!", "Not even four" ] }' gzipped_body = Zlib::Deflate.deflate(unzipped_body) gzipped_body.force_encoding(Encoding::BINARY) if "strings".respond_to?(:force_encoding) http_response.stub(:body).and_return gzipped_body http_response.stub(:read_body) @rest.stub(:sleep) @rest.stub(:http_retry_count).and_return(0) @http_client.stub(:request).and_yield(http_response).and_return(http_response) lambda {@rest.request(:GET, @url)}.should raise_error(Net::HTTPFatalError) @log_stringio.string.should match(Regexp.escape('INFO: HTTP Request Returned 500 drooling from inside of mouth: Ears get sore!, Not even four')) end it "should raise an exception on an unsuccessful request" do http_response = Net::HTTPServerError.new("1.1", "500", "drooling from inside of mouth") http_response.stub(:body) http_response.stub(:read_body) @rest.stub(:sleep) @http_client.stub(:request).and_yield(http_response).and_return(http_response) lambda {@rest.request(:GET, @url)}.should raise_error(Net::HTTPFatalError) end end end context "when streaming downloads to a tempfile" do before do @tempfile = Tempfile.open("chef-rspec-rest_spec-line-#{__LINE__}--") Tempfile.stub(:new).with("chef-rest").and_return(@tempfile) @request_mock = {} Net::HTTP::Get.stub(:new).and_return(@request_mock) @http_response = Net::HTTPSuccess.new("1.1",200, "it-works") @http_response.stub(:read_body) @http_client.stub(:request).and_yield(@http_response).and_return(@http_response) end after do @tempfile.close! end it " build a new HTTP GET request without the application/json accept header" do expected_headers = {'Accept' => "*/*", 'X-Chef-Version' => Chef::VERSION, 'Accept-Encoding' => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE} Net::HTTP::Get.should_receive(:new).with("/?foo=bar", expected_headers).and_return(@request_mock) @rest.streaming_request(@url, {}) end it "returns a tempfile containing the streamed response body" do @rest.streaming_request(@url, {}).should equal(@tempfile) end it "writes the response body to a tempfile" do @http_response.stub(:read_body).and_yield("real").and_yield("ultimate").and_yield("power") @rest.streaming_request(@url, {}) IO.read(@tempfile.path).chomp.should == "realultimatepower" end it "closes the tempfile" do @rest.streaming_request(@url, {}) @tempfile.should be_closed end it "yields the tempfile containing the streamed response body and then unlinks it when given a block" do @http_response.stub(:read_body).and_yield("real").and_yield("ultimate").and_yield("power") tempfile_path = nil @rest.streaming_request(@url, {}) do |tempfile| tempfile_path = tempfile.path File.exist?(tempfile.path).should be_true IO.read(@tempfile.path).chomp.should == "realultimatepower" end File.exist?(tempfile_path).should be_false end it "does not raise a divide by zero exception if the content's actual size is 0" do @http_response.add_field('Content-Length', "5") @http_response.stub(:read_body).and_yield('') lambda { @rest.streaming_request(@url, {}) }.should_not raise_error end it "does not raise a divide by zero exception when the Content-Length is 0" do @http_response.add_field('Content-Length', "0") @http_response.stub(:read_body).and_yield("ninja") lambda { @rest.streaming_request(@url, {}) }.should_not raise_error end it "fetches a file and yields the tempfile it is streamed to" do @http_response.stub(:read_body).and_yield("real").and_yield("ultimate").and_yield("power") tempfile_path = nil @rest.fetch("cookbooks/a_cookbook") do |tempfile| tempfile_path = tempfile.path IO.read(@tempfile.path).chomp.should == "realultimatepower" end File.exist?(tempfile_path).should be_false end it "closes and unlinks the tempfile if there is an error while streaming the content to the tempfile" do path = @tempfile.path path.should_not be_nil @tempfile.stub(:write).and_raise(IOError) @rest.fetch("cookbooks/a_cookbook") {|tmpfile| "shouldn't get here"} File.exists?(path).should be_false end it "closes and unlinks the tempfile when the response is a redirect" do tempfile = double("A tempfile", :path => "/tmp/ragefist", :close => true, :binmode => true) tempfile.should_receive(:close!).at_least(1).times Tempfile.stub(:new).with("chef-rest").and_return(tempfile) redirect = Net::HTTPFound.new("1.1", "302", "bob is taking care of that one for me today") redirect.add_field("location", @url.path) redirect.stub(:read_body) @http_client.should_receive(:request).and_yield(redirect).and_return(redirect) @http_client.should_receive(:request).and_yield(@http_response).and_return(@http_response) @rest.fetch("cookbooks/a_cookbook") {|tmpfile| "shouldn't get here"} end it "passes the original block to the redirected request" do http_response = Net::HTTPFound.new("1.1", "302", "bob is taking care of that one for me today") http_response.add_field("location","/that-thing-is-here-now") http_response.stub(:read_body) block_called = false @http_client.stub(:request).and_yield(@http_response).and_return(http_response, @http_response) @rest.fetch("cookbooks/a_cookbook") do |tmpfile| block_called = true end block_called.should be_true end end end context "when following redirects" do before do Chef::Config[:node_name] = "webmonkey.example.com" Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem" @rest = Chef::REST.new(@url) end it "raises a RedirectLimitExceeded when redirected more than 10 times" do redirected = lambda {@rest.follow_redirect { redirected.call }} lambda {redirected.call}.should raise_error(Chef::Exceptions::RedirectLimitExceeded) end it "does not count redirects from previous calls against the redirect limit" do total_redirects = 0 redirected = lambda do @rest.follow_redirect do total_redirects += 1 redirected.call unless total_redirects >= 9 end end lambda {redirected.call}.should_not raise_error total_redirects = 0 lambda {redirected.call}.should_not raise_error end it "does not sign the redirected request when sign_on_redirect is false" do @rest.sign_on_redirect = false @rest.follow_redirect { @rest.sign_requests?.should be_false } end it "resets sign_requests to the original value after following an unsigned redirect" do @rest.sign_on_redirect = false @rest.sign_requests?.should be_true @rest.follow_redirect { @rest.sign_requests?.should be_false } @rest.sign_requests?.should be_true end it "configures the redirect limit" do total_redirects = 0 redirected = lambda do @rest.follow_redirect do total_redirects += 1 redirected.call unless total_redirects >= 9 end end lambda {redirected.call}.should_not raise_error total_redirects = 0 @rest.redirect_limit = 3 lambda {redirected.call}.should raise_error(Chef::Exceptions::RedirectLimitExceeded) end end end chef-11.8.2/spec/unit/resource_spec.rb0000644000004100000410000010240112254362222017635 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Walters () # Author:: Tim Hinderliter () # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2008-2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' class ResourceTestHarness < Chef::Resource provider_base Chef::Provider::Package end describe Chef::Resource do before(:each) do @cookbook_repo_path = File.join(CHEF_SPEC_DATA, 'cookbooks') @cookbook_collection = Chef::CookbookCollection.new(Chef::CookbookLoader.new(@cookbook_repo_path)) @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) @resource = Chef::Resource.new("funk", @run_context) end describe "when inherited" do it "adds an entry to a list of subclasses" do subclass = Class.new(Chef::Resource) Chef::Resource.resource_classes.should include(subclass) end it "keeps track of subclasses of subclasses" do subclass = Class.new(Chef::Resource) subclass_of_subclass = Class.new(subclass) Chef::Resource.resource_classes.should include(subclass_of_subclass) end end describe "when declaring the identity attribute" do it "has no identity attribute by default" do Chef::Resource.identity_attr.should be_nil end it "sets an identity attribute" do resource_class = Class.new(Chef::Resource) resource_class.identity_attr(:path) resource_class.identity_attr.should == :path end it "inherits an identity attribute from a superclass" do resource_class = Class.new(Chef::Resource) resource_subclass = Class.new(resource_class) resource_class.identity_attr(:package_name) resource_subclass.identity_attr.should == :package_name end it "overrides the identity attribute from a superclass when the identity attr is set" do resource_class = Class.new(Chef::Resource) resource_subclass = Class.new(resource_class) resource_class.identity_attr(:package_name) resource_subclass.identity_attr(:something_else) resource_subclass.identity_attr.should == :something_else end end describe "when no identity attribute has been declared" do before do @resource_sans_id = Chef::Resource.new("my-name") end # Would rather force identity attributes to be set for everything, # but that's not plausible for back compat reasons. it "uses the name as the identity" do @resource_sans_id.identity.should == "my-name" end end describe "when an identity attribute has been declared" do before do @file_resource_class = Class.new(Chef::Resource) do identity_attr :path attr_accessor :path end @file_resource = @file_resource_class.new("identity-attr-test") @file_resource.path = "/tmp/foo.txt" end it "gives the value of its identity attribute" do @file_resource.identity.should == "/tmp/foo.txt" end end describe "when declaring state attributes" do it "has no state_attrs by default" do Chef::Resource.state_attrs.should be_empty end it "sets a list of state attributes" do resource_class = Class.new(Chef::Resource) resource_class.state_attrs(:checksum, :owner, :group, :mode) resource_class.state_attrs.should =~ [:checksum, :owner, :group, :mode] end it "inherits state attributes from the superclass" do resource_class = Class.new(Chef::Resource) resource_subclass = Class.new(resource_class) resource_class.state_attrs(:checksum, :owner, :group, :mode) resource_subclass.state_attrs.should =~ [:checksum, :owner, :group, :mode] end it "combines inherited state attributes with non-inherited state attributes" do resource_class = Class.new(Chef::Resource) resource_subclass = Class.new(resource_class) resource_class.state_attrs(:checksum, :owner) resource_subclass.state_attrs(:group, :mode) resource_subclass.state_attrs.should =~ [:checksum, :owner, :group, :mode] end end describe "when a set of state attributes has been declared" do before do @file_resource_class = Class.new(Chef::Resource) do state_attrs :checksum, :owner, :group, :mode attr_accessor :checksum attr_accessor :owner attr_accessor :group attr_accessor :mode end @file_resource = @file_resource_class.new("describe-state-test") @file_resource.checksum = "abc123" @file_resource.owner = "root" @file_resource.group = "wheel" @file_resource.mode = "0644" end it "describes its state" do resource_state = @file_resource.state resource_state.keys.should =~ [:checksum, :owner, :group, :mode] resource_state[:checksum].should == "abc123" resource_state[:owner].should == "root" resource_state[:group].should == "wheel" resource_state[:mode].should == "0644" end end describe "load_prior_resource" do before(:each) do @prior_resource = Chef::Resource.new("funk") @prior_resource.supports(:funky => true) @prior_resource.source_line @prior_resource.allowed_actions << :funkytown @prior_resource.action(:funkytown) @resource.allowed_actions << :funkytown @run_context.resource_collection << @prior_resource end it "should load the attributes of a prior resource" do @resource.load_prior_resource @resource.supports.should == { :funky => true } end it "should not inherit the action from the prior resource" do @resource.load_prior_resource @resource.action.should_not == @prior_resource.action end end describe "name" do it "should have a name" do @resource.name.should eql("funk") end it "should let you set a new name" do @resource.name "monkey" @resource.name.should eql("monkey") end it "should not be valid without a name" do lambda { @resource.name false }.should raise_error(ArgumentError) end it "should always have a string for name" do lambda { @resource.name Hash.new }.should raise_error(ArgumentError) end end describe "noop" do it "should accept true or false for noop" do lambda { @resource.noop true }.should_not raise_error(ArgumentError) lambda { @resource.noop false }.should_not raise_error(ArgumentError) lambda { @resource.noop "eat it" }.should raise_error(ArgumentError) end end describe "notifies" do it "should make notified resources appear in the actions hash" do @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee") @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "coffee") @resource.delayed_notifications.detect{|e| e.resource.name == "coffee" && e.action == :reload}.should_not be_nil end it "should make notified resources be capable of acting immediately" do @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee") @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "coffee"), :immediate @resource.immediate_notifications.detect{|e| e.resource.name == "coffee" && e.action == :reload}.should_not be_nil end it "should raise an exception if told to act in other than :delay or :immediate(ly)" do @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee") lambda { @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "coffee"), :someday }.should raise_error(ArgumentError) end it "should allow multiple notified resources appear in the actions hash" do @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee") @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "coffee") @resource.delayed_notifications.detect{|e| e.resource.name == "coffee" && e.action == :reload}.should_not be_nil @run_context.resource_collection << Chef::Resource::ZenMaster.new("beans") @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "beans") @resource.delayed_notifications.detect{|e| e.resource.name == "beans" && e.action == :reload}.should_not be_nil end it "creates a notification for a resource that is not yet in the resource collection" do @resource.notifies(:restart, :service => 'apache') expected_notification = Chef::Resource::Notification.new({:service => "apache"}, :restart, @resource) @resource.delayed_notifications.should include(expected_notification) end it "notifies another resource immediately" do @resource.notifies_immediately(:restart, :service => 'apache') expected_notification = Chef::Resource::Notification.new({:service => "apache"}, :restart, @resource) @resource.immediate_notifications.should include(expected_notification) end it "notifies a resource to take action at the end of the chef run" do @resource.notifies_delayed(:restart, :service => "apache") expected_notification = Chef::Resource::Notification.new({:service => "apache"}, :restart, @resource) @resource.delayed_notifications.should include(expected_notification) end end describe "subscribes" do it "should make resources appear in the actions hash of subscribed nodes" do @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee") zr = @run_context.resource_collection.find(:zen_master => "coffee") @resource.subscribes :reload, zr zr.delayed_notifications.detect{|e| e.resource.name == "funk" && e.action == :reload}.should_not be_nil end it "should make resources appear in the actions hash of subscribed nodes" do @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee") zr = @run_context.resource_collection.find(:zen_master => "coffee") @resource.subscribes :reload, zr zr.delayed_notifications.detect{|e| e.resource.name == @resource.name && e.action == :reload}.should_not be_nil @run_context.resource_collection << Chef::Resource::ZenMaster.new("bean") zrb = @run_context.resource_collection.find(:zen_master => "bean") zrb.subscribes :reload, zr zr.delayed_notifications.detect{|e| e.resource.name == @resource.name && e.action == :reload}.should_not be_nil end it "should make subscribed resources be capable of acting immediately" do @run_context.resource_collection << Chef::Resource::ZenMaster.new("coffee") zr = @run_context.resource_collection.find(:zen_master => "coffee") @resource.subscribes :reload, zr, :immediately zr.immediate_notifications.detect{|e| e.resource.name == @resource.name && e.action == :reload}.should_not be_nil end end describe "defined_at" do it "should correctly parse source_line on unix-like operating systems" do @resource.source_line = "/some/path/to/file.rb:80:in `wombat_tears'" @resource.defined_at.should == "/some/path/to/file.rb line 80" end it "should correctly parse source_line on Windows" do @resource.source_line = "C:/some/path/to/file.rb:80 in 1`wombat_tears'" @resource.defined_at.should == "C:/some/path/to/file.rb line 80" end it "should include the cookbook and recipe when it knows it" do @resource.source_line = "/some/path/to/file.rb:80:in `wombat_tears'" @resource.recipe_name = "wombats" @resource.cookbook_name = "animals" @resource.defined_at.should == "animals::wombats line 80" end it "should recognize dynamically defined resources" do @resource.defined_at.should == "dynamically defined" end end describe "to_s" do it "should become a string like resource_name[name]" do zm = Chef::Resource::ZenMaster.new("coffee") zm.to_s.should eql("zen_master[coffee]") end end describe "is" do it "should return the arguments passed with 'is'" do zm = Chef::Resource::ZenMaster.new("coffee") zm.is("one", "two", "three").should == %w|one two three| end it "should allow arguments preceeded by is to methods" do @resource.noop(@resource.is(true)) @resource.noop.should eql(true) end end describe "to_json" do it "should serialize to json" do json = @resource.to_json json.should =~ /json_class/ json.should =~ /instance_vars/ end end describe "to_hash" do it "should convert to a hash" do hash = @resource.to_hash expected_keys = [ :allowed_actions, :params, :provider, :updated, :updated_by_last_action, :before, :supports, :noop, :ignore_failure, :name, :source_line, :action, :retries, :retry_delay, :elapsed_time] (hash.keys - expected_keys).should == [] (expected_keys - hash.keys).should == [] hash[:name].should eql("funk") end end describe "self.json_create" do it "should deserialize itself from json" do json = @resource.to_json serialized_node = Chef::JSONCompat.from_json(json) serialized_node.should be_a_kind_of(Chef::Resource) serialized_node.name.should eql(@resource.name) end end describe "supports" do it "should allow you to set what features this resource supports" do support_hash = { :one => :two } @resource.supports(support_hash) @resource.supports.should eql(support_hash) end it "should return the current value of supports" do @resource.supports.should == {} end end describe "ignore_failure" do it "should default to throwing an error if a provider fails for a resource" do @resource.ignore_failure.should == false end it "should allow you to set whether a provider should throw exceptions with ignore_failure" do @resource.ignore_failure(true) @resource.ignore_failure.should == true end it "should allow you to epic_fail" do @resource.epic_fail(true) @resource.epic_fail.should == true end end describe "retries" do it "should default to not retrying if a provider fails for a resource" do @resource.retries.should == 0 end it "should allow you to set how many retries a provider should attempt after a failure" do @resource.retries(2) @resource.retries.should == 2 end it "should default to a retry delay of 2 seconds" do @resource.retry_delay.should == 2 end it "should allow you to set the retry delay" do @resource.retry_delay(10) @resource.retry_delay.should == 10 end end describe "setting the base provider class for the resource" do it "defaults to Chef::Provider for the base class" do Chef::Resource.provider_base.should == Chef::Provider end it "allows the base provider to be overriden by a " do ResourceTestHarness.provider_base.should == Chef::Provider::Package end end it "supports accessing the node via the @node instance variable [DEPRECATED]" do @resource.instance_variable_get(:@node).inspect.should == @node.inspect end it "runs an action by finding its provider, loading the current resource and then running the action" do pending end describe "when updated by a provider" do before do @resource.updated_by_last_action(true) end it "records that it was updated" do @resource.should be_updated end it "records that the last action updated the resource" do @resource.should be_updated_by_last_action end describe "and then run again without being updated" do before do @resource.updated_by_last_action(false) end it "reports that it is updated" do @resource.should be_updated end it "reports that it was not updated by the last action" do @resource.should_not be_updated_by_last_action end end end describe "when invoking its action" do before do @resource = Chef::Resource.new("provided", @run_context) @resource.provider = Chef::Provider::SnakeOil @node.automatic_attrs[:platform] = "fubuntu" @node.automatic_attrs[:platform_version] = '10.04' end it "does not run only_if if no only_if command is given" do @resource.not_if.clear @resource.run_action(:purr) end it "runs runs an only_if when one is given" do snitch_variable = nil @resource.only_if { snitch_variable = true } @resource.only_if.first.positivity.should == :only_if #Chef::Mixin::Command.should_receive(:only_if).with(true, {}).and_return(false) @resource.run_action(:purr) snitch_variable.should be_true end it "runs multiple only_if conditionals" do snitch_var1, snitch_var2 = nil, nil @resource.only_if { snitch_var1 = 1 } @resource.only_if { snitch_var2 = 2 } @resource.run_action(:purr) snitch_var1.should == 1 snitch_var2.should == 2 end it "accepts command options for only_if conditionals" do Chef::Resource::Conditional.any_instance.should_receive(:evaluate_command).at_least(1).times @resource.only_if("true", :cwd => '/tmp') @resource.only_if.first.command_opts.should == {:cwd => '/tmp'} @resource.run_action(:purr) end it "runs not_if as a command when it is a string" do Chef::Resource::Conditional.any_instance.should_receive(:evaluate_command).at_least(1).times @resource.not_if "pwd" @resource.run_action(:purr) end it "runs not_if as a block when it is a ruby block" do Chef::Resource::Conditional.any_instance.should_receive(:evaluate_block).at_least(1).times @resource.not_if { puts 'foo' } @resource.run_action(:purr) end it "does not run not_if if no not_if command is given" do @resource.run_action(:purr) end it "accepts command options for not_if conditionals" do @resource.not_if("pwd" , :cwd => '/tmp') @resource.not_if.first.command_opts.should == {:cwd => '/tmp'} end it "accepts multiple not_if conditionals" do snitch_var1, snitch_var2 = true, true @resource.not_if {snitch_var1 = nil} @resource.not_if {snitch_var2 = false} @resource.run_action(:purr) snitch_var1.should be_nil snitch_var2.should be_false end end describe "should_skip?" do before do @resource = Chef::Resource::Cat.new("sugar", @run_context) end it "should return false by default" do @resource.should_skip?(:purr).should be_false end it "should return false when if_only is met" do @resource.only_if { true } @resource.should_skip?(:purr).should be_false end it "should return true when if_only is not met" do @resource.only_if { false } @resource.should_skip?(:purr).should be_true end it "should return true when not_if is met" do @resource.not_if { true } @resource.should_skip?(:purr).should be_true end it "should return false when if_only is not met" do @resource.not_if { false } @resource.should_skip?(:purr).should be_false end it "should return true when if_only is met but also not_if is met" do @resource.only_if { true } @resource.not_if { true } @resource.should_skip?(:purr).should be_true end it "should return true when one of multiple if_only's is not met" do @resource.only_if { true } @resource.only_if { false } @resource.only_if { true } @resource.should_skip?(:purr).should be_true end it "should return true when one of multiple not_if's is met" do @resource.not_if { false } @resource.not_if { true } @resource.not_if { false } @resource.should_skip?(:purr).should be_true end it "should return true when action is :nothing" do @resource.should_skip?(:nothing).should be_true end it "should return true when action is :nothing ignoring only_if/not_if conditionals" do @resource.only_if { true } @resource.not_if { false } @resource.should_skip?(:nothing).should be_true end it "should print \"skipped due to action :nothing\" message for doc formatter when action is :nothing" do fdoc = Chef::Formatters.new(:doc, STDOUT, STDERR) @run_context.stub!(:events).and_return(fdoc) fdoc.should_receive(:puts).with(" (skipped due to action :nothing)") @resource.should_skip?(:nothing) end end describe "when resource action is :nothing" do before do @resource1 = Chef::Resource::Cat.new("sugar", @run_context) @resource1.action = :nothing @node.automatic_attrs[:platform] = "fubuntu" @node.automatic_attrs[:platform_version] = '10.04' end it "should not run only_if/not_if conditionals (CHEF-972)" do snitch_var1 = 0 @resource1.only_if { snitch_var1 = 1 } @resource1.not_if { snitch_var1 = 2 } @resource1.run_action(:nothing) snitch_var1.should == 0 end it "should run only_if/not_if conditionals when notified to run another action (CHEF-972)" do snitch_var1 = snitch_var2 = 0 @runner = Chef::Runner.new(@run_context) Chef::Platform.set( :resource => :cat, :provider => Chef::Provider::SnakeOil ) @resource1.only_if { snitch_var1 = 1 } @resource1.not_if { snitch_var2 = 2 } @resource2 = Chef::Resource::Cat.new("coffee", @run_context) @resource2.notifies :purr, @resource1 @resource2.action = :purr @run_context.resource_collection << @resource1 @run_context.resource_collection << @resource2 @runner.converge snitch_var1.should == 1 snitch_var2.should == 2 end end describe "building the platform map" do it 'adds mappings for a single platform' do klz = Class.new(Chef::Resource) Chef::Resource.platform_map.should_receive(:set).with( :platform => :autobots, :short_name => :dinobot, :resource => klz ) klz.provides :dinobot, :on_platforms => ['autobots'] end it 'adds mappings for multiple platforms' do klz = Class.new(Chef::Resource) Chef::Resource.platform_map.should_receive(:set).twice klz.provides :energy, :on_platforms => ['autobots','decepticons'] end it 'adds mappings for all platforms' do klz = Class.new(Chef::Resource) Chef::Resource.platform_map.should_receive(:set).with( :short_name => :tape_deck, :resource => klz ) klz.provides :tape_deck end end describe "lookups from the platform map" do before(:each) do @node = Chef::Node.new @node.name("bumblebee") @node.automatic[:platform] = "autobots" @node.automatic[:platform_version] = "6.1" Object.const_set('Soundwave', Class.new(Chef::Resource)) Object.const_set('Grimlock', Class.new(Chef::Resource){ provides :dinobot, :on_platforms => ['autobots'] }) end after(:each) do Object.send(:remove_const, :Soundwave) Object.send(:remove_const, :Grimlock) end describe "resource_for_platform" do it 'return a resource by short_name and platform' do Chef::Resource.resource_for_platform(:dinobot,'autobots','6.1').should eql(Grimlock) end it "returns a resource by short_name if nothing else matches" do Chef::Resource.resource_for_node(:soundwave, @node).should eql(Soundwave) end end describe "resource_for_node" do it "returns a resource by short_name and node" do Chef::Resource.resource_for_node(:dinobot, @node).should eql(Grimlock) end it "returns a resource by short_name if nothing else matches" do Chef::Resource.resource_for_node(:soundwave, @node).should eql(Soundwave) end end end describe "when creating notifications" do describe "with a string resource spec" do it "creates a delayed notification when timing is not specified" do @resource.notifies(:run, "execute[foo]") @run_context.delayed_notification_collection.should have(1).notifications end it "creates a delayed notification when :delayed is not specified" do @resource.notifies(:run, "execute[foo]", :delayed) @run_context.delayed_notification_collection.should have(1).notifications end it "creates an immediate notification when :immediate is specified" do @resource.notifies(:run, "execute[foo]", :immediate) @run_context.immediate_notification_collection.should have(1).notifications end it "creates an immediate notification when :immediately is specified" do @resource.notifies(:run, "execute[foo]", :immediately) @run_context.immediate_notification_collection.should have(1).notifications end describe "with a syntax error in the resource spec" do it "raises an exception immmediately" do lambda do @resource.notifies(:run, "typo[missing-closing-bracket") end.should raise_error(Chef::Exceptions::InvalidResourceSpecification) end end end describe "with a resource reference" do before do @notified_resource = Chef::Resource.new("punk", @run_context) end it "creates a delayed notification when timing is not specified" do @resource.notifies(:run, @notified_resource) @run_context.delayed_notification_collection.should have(1).notifications end it "creates a delayed notification when :delayed is not specified" do @resource.notifies(:run, @notified_resource, :delayed) @run_context.delayed_notification_collection.should have(1).notifications end it "creates an immediate notification when :immediate is specified" do @resource.notifies(:run, @notified_resource, :immediate) @run_context.immediate_notification_collection.should have(1).notifications end it "creates an immediate notification when :immediately is specified" do @resource.notifies(:run, @notified_resource, :immediately) @run_context.immediate_notification_collection.should have(1).notifications end end end end describe Chef::Resource::Notification do before do @notification = Chef::Resource::Notification.new(:service_apache, :restart, :template_httpd_conf) end it "has a resource to be notified" do @notification.resource.should == :service_apache end it "has an action to take on the service" do @notification.action.should == :restart end it "has a notifying resource" do @notification.notifying_resource.should == :template_httpd_conf end it "is a duplicate of another notification with the same target resource and action" do other = Chef::Resource::Notification.new(:service_apache, :restart, :sync_web_app_code) @notification.duplicates?(other).should be_true end it "is not a duplicate of another notification if the actions differ" do other = Chef::Resource::Notification.new(:service_apache, :enable, :install_apache) @notification.duplicates?(other).should be_false end it "is not a duplicate of another notification if the target resources differ" do other = Chef::Resource::Notification.new(:service_sshd, :restart, :template_httpd_conf) @notification.duplicates?(other).should be_false end it "raises an ArgumentError if you try to check a non-ducktype object for duplication" do lambda {@notification.duplicates?(:not_a_notification)}.should raise_error(ArgumentError) end it "takes no action to resolve a resource reference that doesn't need to be resolved" do @keyboard_cat = Chef::Resource::Cat.new("keyboard_cat") @notification.resource = @keyboard_cat @long_cat = Chef::Resource::Cat.new("long_cat") @notification.notifying_resource = @long_cat @resource_collection = Chef::ResourceCollection.new # would raise an error since the resource is not in the collection @notification.resolve_resource_reference(@resource_collection) @notification.resource.should == @keyboard_cat end it "resolves a lazy reference to a resource" do @notification.resource = {:cat => "keyboard_cat"} @keyboard_cat = Chef::Resource::Cat.new("keyboard_cat") @resource_collection = Chef::ResourceCollection.new @resource_collection << @keyboard_cat @long_cat = Chef::Resource::Cat.new("long_cat") @notification.notifying_resource = @long_cat @notification.resolve_resource_reference(@resource_collection) @notification.resource.should == @keyboard_cat end it "resolves a lazy reference to its notifying resource" do @keyboard_cat = Chef::Resource::Cat.new("keyboard_cat") @notification.resource = @keyboard_cat @notification.notifying_resource = {:cat => "long_cat"} @long_cat = Chef::Resource::Cat.new("long_cat") @resource_collection = Chef::ResourceCollection.new @resource_collection << @long_cat @notification.resolve_resource_reference(@resource_collection) @notification.notifying_resource.should == @long_cat end it "resolves lazy references to both its resource and its notifying resource" do @notification.resource = {:cat => "keyboard_cat"} @keyboard_cat = Chef::Resource::Cat.new("keyboard_cat") @resource_collection = Chef::ResourceCollection.new @resource_collection << @keyboard_cat @notification.notifying_resource = {:cat => "long_cat"} @long_cat = Chef::Resource::Cat.new("long_cat") @resource_collection << @long_cat @notification.resolve_resource_reference(@resource_collection) @notification.resource.should == @keyboard_cat @notification.notifying_resource.should == @long_cat end it "raises a RuntimeError if you try to reference multiple resources" do @notification.resource = {:cat => ["keyboard_cat", "cheez_cat"]} @keyboard_cat = Chef::Resource::Cat.new("keyboard_cat") @cheez_cat = Chef::Resource::Cat.new("cheez_cat") @resource_collection = Chef::ResourceCollection.new @resource_collection << @keyboard_cat @resource_collection << @cheez_cat @long_cat = Chef::Resource::Cat.new("long_cat") @notification.notifying_resource = @long_cat lambda {@notification.resolve_resource_reference(@resource_collection)}.should raise_error(RuntimeError) end it "raises a RuntimeError if you try to reference multiple notifying resources" do @notification.notifying_resource = {:cat => ["long_cat", "cheez_cat"]} @long_cat = Chef::Resource::Cat.new("long_cat") @cheez_cat = Chef::Resource::Cat.new("cheez_cat") @resource_collection = Chef::ResourceCollection.new @resource_collection << @long_cat @resource_collection << @cheez_cat @keyboard_cat = Chef::Resource::Cat.new("keyboard_cat") @notification.resource = @keyboard_cat lambda {@notification.resolve_resource_reference(@resource_collection)}.should raise_error(RuntimeError) end it "raises a RuntimeError if it can't find a resource in the resource collection when resolving a lazy reference" do @notification.resource = {:cat => "keyboard_cat"} @cheez_cat = Chef::Resource::Cat.new("cheez_cat") @resource_collection = Chef::ResourceCollection.new @resource_collection << @cheez_cat @long_cat = Chef::Resource::Cat.new("long_cat") @notification.notifying_resource = @long_cat lambda {@notification.resolve_resource_reference(@resource_collection)}.should raise_error(RuntimeError) end it "raises a RuntimeError if it can't find a notifying resource in the resource collection when resolving a lazy reference" do @notification.notifying_resource = {:cat => "long_cat"} @cheez_cat = Chef::Resource::Cat.new("cheez_cat") @resource_collection = Chef::ResourceCollection.new @resource_collection << @cheez_cat @keyboard_cat = Chef::Resource::Cat.new("keyboard_cat") @notification.resource = @keyboard_cat lambda {@notification.resolve_resource_reference(@resource_collection)}.should raise_error(RuntimeError) end it "raises an ArgumentError if improper syntax is used in the lazy reference to its resource" do @notification.resource = "cat => keyboard_cat" @keyboard_cat = Chef::Resource::Cat.new("keyboard_cat") @resource_collection = Chef::ResourceCollection.new @resource_collection << @keyboard_cat @long_cat = Chef::Resource::Cat.new("long_cat") @notification.notifying_resource = @long_cat lambda {@notification.resolve_resource_reference(@resource_collection)}.should raise_error(ArgumentError) end it "raises an ArgumentError if improper syntax is used in the lazy reference to its notifying resource" do @notification.notifying_resource = "cat => long_cat" @long_cat = Chef::Resource::Cat.new("long_cat") @resource_collection = Chef::ResourceCollection.new @resource_collection << @long_cat @keyboard_cat = Chef::Resource::Cat.new("keyboard_cat") @notification.resource = @keyboard_cat lambda {@notification.resolve_resource_reference(@resource_collection)}.should raise_error(ArgumentError) end # Create test to resolve lazy references to both notifying resource and dest. resource # Create tests to check proper error raising end chef-11.8.2/spec/unit/encrypted_data_bag_item_spec.rb0000644000004100000410000002452312254362222022633 0ustar www-datawww-data# # Author:: Seth Falcon () # Copyright:: Copyright 2010-2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/encrypted_data_bag_item' module Version0Encryptor def self.encrypt_value(plaintext_data, key) data = plaintext_data.to_yaml cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc") cipher.encrypt cipher.pkcs5_keyivgen(key) encrypted_bytes = cipher.update(data) encrypted_bytes << cipher.final Base64.encode64(encrypted_bytes) end end describe Chef::EncryptedDataBagItem::Encryptor do subject(:encryptor) { described_class.new(plaintext_data, key) } let(:plaintext_data) { {"foo" => "bar"} } let(:key) { "passwd" } it "encrypts to format version 1 by default" do encryptor.should be_a_kind_of(Chef::EncryptedDataBagItem::Encryptor::Version1Encryptor) end describe "generating a random IV" do it "generates a new IV for each encryption pass" do encryptor2 = Chef::EncryptedDataBagItem::Encryptor.new(plaintext_data, key) # No API in ruby OpenSSL to get the iv it used for the encryption back # out. Instead we test if the encrypted data is the same. If it *is* the # same, we assume the IV was the same each time. encryptor.encrypted_data.should_not eq encryptor2.encrypted_data end end describe "when encrypting a non-hash non-array value" do let(:plaintext_data) { 5 } it "serializes the value in a de-serializable way" do Chef::JSONCompat.from_json(subject.serialized_data)["json_wrapper"].should eq 5 end end describe "wrapping secret values in an envelope" do it "wraps the encrypted data in an envelope with the iv and version" do final_data = encryptor.for_encrypted_item final_data["encrypted_data"].should eq encryptor.encrypted_data final_data["iv"].should eq Base64.encode64(encryptor.iv) final_data["version"].should eq 1 final_data["cipher"].should eq"aes-256-cbc" end end describe "when using version 2 format" do before do Chef::Config[:data_bag_encrypt_version] = 2 end it "creates a version 2 encryptor" do encryptor.should be_a_kind_of(Chef::EncryptedDataBagItem::Encryptor::Version2Encryptor) end it "generates an hmac based on ciphertext including iv" do encryptor2 = Chef::EncryptedDataBagItem::Encryptor.new(plaintext_data, key) encryptor.hmac.should_not eq(encryptor2.hmac) end it "includes the hmac in the envelope" do final_data = encryptor.for_encrypted_item final_data["hmac"].should eq(encryptor.hmac) end end end describe Chef::EncryptedDataBagItem::Decryptor do subject(:decryptor) { described_class.for(encrypted_value, decryption_key) } let(:plaintext_data) { {"foo" => "bar"} } let(:encryption_key) { "passwd" } let(:decryption_key) { encryption_key } context "when decrypting a version 2 (JSON+aes-256-cbc+hmac-sha256+random iv) encrypted value" do let(:encrypted_value) do Chef::EncryptedDataBagItem::Encryptor::Version2Encryptor.new(plaintext_data, encryption_key).for_encrypted_item end let(:bogus_hmac) do digest = OpenSSL::Digest::Digest.new("sha256") raw_hmac = OpenSSL::HMAC.digest(digest, "WRONG", encrypted_value["encrypted_data"]) Base64.encode64(raw_hmac) end it "rejects the data if the hmac is wrong" do encrypted_value["hmac"] = bogus_hmac lambda { decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::DecryptionFailure) end it "rejects the data if the hmac is missing" do encrypted_value.delete("hmac") lambda { decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::DecryptionFailure) end end context "when decrypting a version 1 (JSON+aes-256-cbc+random iv) encrypted value" do let(:encrypted_value) do Chef::EncryptedDataBagItem::Encryptor.new(plaintext_data, encryption_key).for_encrypted_item end it "selects the correct strategy for version 1" do decryptor.should be_a_kind_of Chef::EncryptedDataBagItem::Decryptor::Version1Decryptor end it "decrypts the encrypted value" do decryptor.decrypted_data.should eq({"json_wrapper" => plaintext_data}.to_json) end it "unwraps the encrypted data and returns it" do decryptor.for_decrypted_item.should eq plaintext_data end describe "and the decryption step returns invalid data" do it "raises a decryption failure error" do # Over a large number of tests on a variety of systems, we occasionally # see the decryption step "succeed" but return invalid data (e.g., not # the original plain text) [CHEF-3858] decryptor.should_receive(:decrypted_data).and_return("lksajdf") lambda { decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::DecryptionFailure) end end context "and the provided key is incorrect" do let(:decryption_key) { "wrong-passwd" } it "raises a sensible error" do lambda { decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::DecryptionFailure) end end context "and the cipher is not supported" do let(:encrypted_value) do ev = Chef::EncryptedDataBagItem::Encryptor.new(plaintext_data, encryption_key).for_encrypted_item ev["cipher"] = "aes-256-foo" ev end it "raises a sensible error" do lambda { decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::UnsupportedCipher) end end context "and version 2 format is required" do before do Chef::Config[:data_bag_decrypt_minimum_version] = 2 end it "raises an error attempting to decrypt" do lambda { decryptor }.should raise_error(Chef::EncryptedDataBagItem::UnacceptableEncryptedDataBagItemFormat) end end end context "when decrypting a version 0 (YAML+aes-256-cbc+no iv) encrypted value" do let(:encrypted_value) do Version0Encryptor.encrypt_value(plaintext_data, encryption_key) end it "selects the correct strategy for version 0" do decryptor.should be_a_kind_of(Chef::EncryptedDataBagItem::Decryptor::Version0Decryptor) end it "decrypts the encrypted value" do decryptor.for_decrypted_item.should eq plaintext_data end context "and version 1 format is required" do before do Chef::Config[:data_bag_decrypt_minimum_version] = 1 end it "raises an error attempting to decrypt" do lambda { decryptor }.should raise_error(Chef::EncryptedDataBagItem::UnacceptableEncryptedDataBagItemFormat) end end end end describe Chef::EncryptedDataBagItem do subject { described_class } let(:encrypted_data_bag_item) { subject.new(encoded_data, secret) } let(:plaintext_data) {{ "id" => "item_name", "greeting" => "hello", "nested" => { "a1" => [1, 2, 3], "a2" => { "b1" => true }} }} let(:secret) { "abc123SECRET" } let(:encoded_data) { subject.encrypt_data_bag_item(plaintext_data, secret) } describe "encrypting" do it "doesn't encrypt the 'id' key" do encoded_data["id"].should eq "item_name" end it "encrypts non-collection objects" do encoded_data["greeting"]["version"].should eq 1 encoded_data["greeting"].should have_key("iv") iv = encoded_data["greeting"]["iv"] encryptor = Chef::EncryptedDataBagItem::Encryptor.new("hello", secret, iv) encoded_data["greeting"]["encrypted_data"].should eq(encryptor.for_encrypted_item["encrypted_data"]) end it "encrypts nested values" do encoded_data["nested"]["version"].should eq 1 encoded_data["nested"].should have_key("iv") iv = encoded_data["nested"]["iv"] encryptor = Chef::EncryptedDataBagItem::Encryptor.new(plaintext_data["nested"], secret, iv) encoded_data["nested"]["encrypted_data"].should eq(encryptor.for_encrypted_item["encrypted_data"]) end end describe "decrypting" do it "doesn't try to decrypt 'id'" do encrypted_data_bag_item["id"].should eq(plaintext_data["id"]) end it "decrypts 'greeting'" do encrypted_data_bag_item["greeting"].should eq(plaintext_data["greeting"]) end it "decrypts 'nested'" do encrypted_data_bag_item["nested"].should eq(plaintext_data["nested"]) end it "decrypts everyting via to_hash" do encrypted_data_bag_item.to_hash.should eq(plaintext_data) end it "handles missing keys gracefully" do encrypted_data_bag_item["no-such-key"].should be_nil end end describe "loading" do it "should defer to Chef::DataBagItem.load" do Chef::DataBagItem.stub(:load).with(:the_bag, "my_codes").and_return(encoded_data) edbi = Chef::EncryptedDataBagItem.load(:the_bag, "my_codes", secret) edbi["greeting"].should eq(plaintext_data["greeting"]) end end describe ".load_secret" do subject(:loaded_secret) { Chef::EncryptedDataBagItem.load_secret(path) } let(:path) { "/var/mysecret" } let(:secret) { "opensesame" } let(:stubbed_path) { path } before do ::File.stub(:exist?).with(stubbed_path).and_return(true) IO.stub(:read).with(stubbed_path).and_return(secret) Kernel.stub(:open).with(path).and_return(StringIO.new(secret)) end it "reads from a specified path" do loaded_secret.should eq secret end context "path argument is nil" do let(:path) { nil } let(:stubbed_path) { "/etc/chef/encrypted_data_bag_secret" } it "reads from Chef::Config[:encrypted_data_bag_secret]" do Chef::Config[:encrypted_data_bag_secret] = stubbed_path loaded_secret.should eq secret end end context "path argument is a URL" do let(:path) { "http://www.opscode.com/" } it "reads the URL" do loaded_secret.should eq secret end end end end chef-11.8.2/spec/unit/run_context/0000755000004100000410000000000012254362222017021 5ustar www-datawww-datachef-11.8.2/spec/unit/run_context/cookbook_compiler_spec.rb0000644000004100000410000001514012254362222024061 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'support/lib/library_load_order' # These tests rely on fixture data in spec/data/run_context/cookbooks. # # Dependencies (circular or not) are specified by `depends` directives in the # metadata of these cookbooks. # # Side effects used to verify the behavior are implemented as code in the various file types. # describe Chef::RunContext::CookbookCompiler do let(:node) { Chef::Node.new } let(:events) { Chef::EventDispatch::Dispatcher.new } let(:cookbook_loader) do cl = Chef::CookbookLoader.new(chef_repo_path) cl.load_cookbooks cl end let(:run_context) { Chef::RunContext.new(node, cookbook_collection, events) } let(:chef_repo_path) { File.expand_path(File.join(CHEF_SPEC_DATA, "run_context", "cookbooks")) } let(:cookbook_collection) { Chef::CookbookCollection.new(cookbook_loader) } # Lazy evaluation of `expansion` here is used to mutate the run list before expanding it let(:run_list_expansion) { node.run_list.expand('_default') } let(:compiler) do Chef::RunContext::CookbookCompiler.new(run_context, run_list_expansion, events) end describe "loading attribute files" do # Attribute files in the fixture data will append their # "cookbook_name::attribute_file_name" to the node's `:attr_load_order` # attribute when loaded. it "loads default.rb first, then other files in sort order" do node.run_list("dependency1::default") compiler.compile_attributes node[:attr_load_order].should == ["dependency1::default", "dependency1::aa_first", "dependency1::zz_last"] end it "loads dependencies before loading the depending cookbook's attributes" do # Also make sure that attributes aren't loaded twice if we have two # recipes from the same cookbook in the run list node.run_list("test-with-deps::default", "test-with-deps::server") compiler.compile_attributes # dependencies are stored in a hash so therefore unordered, but they should be loaded in sort order node[:attr_load_order].should == ["dependency1::default", "dependency1::aa_first", "dependency1::zz_last", "dependency2::default", "test-with-deps::default"] end it "does not follow infinite dependency loops" do node.run_list("test-with-circular-deps::default") # Circular deps should not cause infinite loops compiler.compile_attributes node[:attr_load_order].should == ["circular-dep2::default", "circular-dep1::default", "test-with-circular-deps::default"] end it "loads attributes from cookbooks that don't have a default.rb attribute file" do node.run_list("no-default-attr::default.rb") compiler.compile_attributes node[:attr_load_order].should == ["no-default-attr::server"] end end describe "loading libraries" do before do LibraryLoadOrder.reset! end # One big test for everything. Individual behaviors are tested by the attribute code above. it "loads libraries in run list order" do node.run_list("test-with-deps::default", "test-with-circular-deps::default") compiler.compile_libraries LibraryLoadOrder.load_order.should == ["dependency1", "dependency2", "test-with-deps", "circular-dep2", "circular-dep1", "test-with-circular-deps"] end end describe "loading LWRPs" do before do LibraryLoadOrder.reset! end # One big test for everything. Individual behaviors are tested by the attribute code above. it "loads LWRPs in run list order" do node.run_list("test-with-deps::default", "test-with-circular-deps::default") compiler.compile_lwrps LibraryLoadOrder.load_order.should == ["dependency1-provider", "dependency1-resource", "dependency2-provider", "dependency2-resource", "test-with-deps-provider", "test-with-deps-resource", "circular-dep2-provider", "circular-dep2-resource", "circular-dep1-provider", "circular-dep1-resource", "test-with-circular-deps-provider", "test-with-circular-deps-resource"] end end describe "loading resource definitions" do before do LibraryLoadOrder.reset! end # One big test for all load order concerns. Individual behaviors are tested # by the attribute code above. it "loads resource definitions in run list order" do node.run_list("test-with-deps::default", "test-with-circular-deps::default") compiler.compile_resource_definitions LibraryLoadOrder.load_order.should == ["dependency1-definition", "dependency2-definition", "test-with-deps-definition", "circular-dep2-definition", "circular-dep1-definition", "test-with-circular-deps-definition"] end end describe "loading recipes" do # Tests for this behavior are in RunContext's tests end describe "listing cookbook order" do it "should return an array of cookbook names as symbols without duplicates" do node.run_list("test-with-circular-deps::default", "circular-dep1::default", "circular-dep2::default") compiler.cookbook_order.should == [:"circular-dep2", :"circular-dep1", :"test-with-circular-deps"] end end end chef-11.8.2/spec/unit/resource/0000755000004100000410000000000012254362222016300 5ustar www-datawww-datachef-11.8.2/spec/unit/resource/route_spec.rb0000644000004100000410000000606712254362222021006 0ustar www-datawww-data# # Author:: Bryan McLellan (btm@loftninjas.org) # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Bryan McLellan # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Route do before(:each) do @resource = Chef::Resource::Route.new("10.0.0.10") end it "should create a new Chef::Resource::Route" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::Route) end it "should have a name" do @resource.name.should eql("10.0.0.10") end it "should have a default action of 'add'" do @resource.action.should eql([:add]) end it "should accept add or delete for action" do lambda { @resource.action :add }.should_not raise_error(ArgumentError) lambda { @resource.action :delete }.should_not raise_error(ArgumentError) lambda { @resource.action :lolcat }.should raise_error(ArgumentError) end it "should use the object name as the target by default" do @resource.target.should eql("10.0.0.10") end it "should allow you to specify the netmask" do @resource.netmask "255.255.255.0" @resource.netmask.should eql("255.255.255.0") end it "should allow you to specify the gateway" do @resource.gateway "10.0.0.1" @resource.gateway.should eql("10.0.0.1") end it "should allow you to specify the metric" do @resource.metric 10 @resource.metric.should eql(10) end it "should allow you to specify the device" do @resource.device "eth0" @resource.device.should eql("eth0") end it "should allow you to specify the route type" do @resource.route_type "host" @resource.route_type.should eql(:host) end it "should default to a host route type" do @resource.route_type.should eql(:host) end it "should accept a net route type" do @resource.route_type :net @resource.route_type.should eql(:net) end it "should reject any other route_type but :host and :net" do lambda { @resource.route_type "lolcat" }.should raise_error(ArgumentError) end describe "when it has netmask, gateway, and device" do before do @resource.target("charmander") @resource.netmask("lemask") @resource.gateway("111.111.111") @resource.device("forcefield") end it "describes its state" do state = @resource.state state[:netmask].should == "lemask" state[:gateway].should == "111.111.111" end it "returns the target as its identity" do @resource.identity.should == "charmander" end end end chef-11.8.2/spec/unit/resource/git_spec.rb0000644000004100000410000000241212254362222020421 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Git do before(:each) do @git = Chef::Resource::Git.new("my awesome webapp") end it "is a kind of Scm Resource" do @git.should be_a_kind_of(Chef::Resource::Scm) @git.should be_an_instance_of(Chef::Resource::Git) end it "uses the git provider" do @git.provider.should eql(Chef::Provider::Git) end it "uses aliases revision as branch" do @git.branch "HEAD" @git.revision.should eql("HEAD") end it "aliases revision as reference" do @git.reference "v1.0 tag" @git.revision.should eql("v1.0 tag") end end chef-11.8.2/spec/unit/resource/batch_spec.rb0000644000004100000410000000260112254362222020717 0ustar www-datawww-data# # Author:: Adam Edwards () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Batch do before(:each) do node = Chef::Node.new node.default["kernel"] = Hash.new node.default["kernel"][:machine] = :x86_64.to_s run_context = Chef::RunContext.new(node, nil, nil) @resource = Chef::Resource::Batch.new("batch_unit_test", run_context) end it "should create a new Chef::Resource::Batch" do @resource.should be_a_kind_of(Chef::Resource::Batch) end context "windows script" do let(:resource_instance) { @resource } let(:resource_instance_name ) { @resource.command } let(:resource_name) { :batch } let(:interpreter_file_name) { 'cmd.exe' } it_should_behave_like "a Windows script resource" end end chef-11.8.2/spec/unit/resource/pacman_package_spec.rb0000644000004100000410000000232512254362222022553 0ustar www-datawww-data# # Author:: Jan Zimmek () # Copyright:: Copyright (c) 2010 Jan Zimmek # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::PacmanPackage, "initialize" do before(:each) do @resource = Chef::Resource::PacmanPackage.new("foo") end it "should return a Chef::Resource::PacmanPackage" do @resource.should be_a_kind_of(Chef::Resource::PacmanPackage) end it "should set the resource_name to :pacman_package" do @resource.resource_name.should eql(:pacman_package) end it "should set the provider to Chef::Provider::Package::Pacman" do @resource.provider.should eql(Chef::Provider::Package::Pacman) end end chef-11.8.2/spec/unit/resource/deploy_revision_spec.rb0000644000004100000410000000276112254362222023057 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 Daniel DeLeo # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::DeployRevision do it "defaults to the revision deploy provider" do @resource = Chef::Resource::DeployRevision.new("deploy _this_!") @resource.provider.should == Chef::Provider::Deploy::Revision end it "has a name of deploy_revision" do @resource = Chef::Resource::DeployRevision.new("deploy _this_!") @resource.resource_name.should == :deploy_revision end end describe Chef::Resource::DeployBranch do it "defaults to the revision deploy provider" do @resource = Chef::Resource::DeployBranch.new("deploy _this_!") @resource.provider.should == Chef::Provider::Deploy::Revision end it "has a name of deploy_branch" do @resource = Chef::Resource::DeployBranch.new("deploy _this_!") @resource.resource_name.should == :deploy_branch end end chef-11.8.2/spec/unit/resource/group_spec.rb0000644000004100000410000001076512254362222021004 0ustar www-datawww-data# # Author:: AJ Christensen () # Author:: Tyler Cloke (); # Copyright:: Copyright (c) 2008 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Group, "initialize" do before(:each) do @resource = Chef::Resource::Group.new("admin") end it "should create a new Chef::Resource::Group" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::Group) end it "should set the resource_name to :group" do @resource.resource_name.should eql(:group) end it "should set the group_name equal to the argument to initialize" do @resource.group_name.should eql("admin") end it "should default gid to nil" do @resource.gid.should eql(nil) end it "should default members to an empty array" do @resource.members.should eql([]) end it "should alias users to members, also an empty array" do @resource.users.should eql([]) end it "should set action to :create" do @resource.action.should eql(:create) end %w{create remove modify manage}.each do |action| it "should allow action #{action}" do @resource.allowed_actions.detect { |a| a == action.to_sym }.should eql(action.to_sym) end end it "should accept domain groups (@ or \ separator) on non-windows" do lambda { @resource.group_name "domain\@group" }.should_not raise_error(ArgumentError) @resource.group_name.should == "domain\@group" lambda { @resource.group_name "domain\\group" }.should_not raise_error(ArgumentError) @resource.group_name.should == "domain\\group" lambda { @resource.group_name "domain\\group^name" }.should_not raise_error(ArgumentError) @resource.group_name.should == "domain\\group^name" end end describe Chef::Resource::Group, "group_name" do before(:each) do @resource = Chef::Resource::Group.new("admin") end it "should allow a string" do @resource.group_name "pirates" @resource.group_name.should eql("pirates") end it "should not allow a hash" do lambda { @resource.send(:group_name, { :aj => "is freakin awesome" }) }.should raise_error(ArgumentError) end end describe Chef::Resource::Group, "gid" do before(:each) do @resource = Chef::Resource::Group.new("admin") end it "should allow an integer" do @resource.gid 100 @resource.gid.should eql(100) end it "should not allow a hash" do lambda { @resource.send(:gid, { :aj => "is freakin awesome" }) }.should raise_error(ArgumentError) end end describe Chef::Resource::Group, "members" do before(:each) do @resource = Chef::Resource::Group.new("admin") end [ :users, :members].each do |method| it "(#{method}) should allow and convert a string" do @resource.send(method, "aj") @resource.send(method).should eql(["aj"]) end it "(#{method}) should allow an array" do @resource.send(method, [ "aj", "adam" ]) @resource.send(method).should eql( ["aj", "adam"] ) end it "(#{method}) should not allow a hash" do lambda { @resource.send(method, { :aj => "is freakin awesome" }) }.should raise_error(ArgumentError) end end end describe Chef::Resource::Group, "append" do before(:each) do @resource = Chef::Resource::Group.new("admin") end it "should default to false" do @resource.append.should eql(false) end it "should allow a boolean" do @resource.append true @resource.append.should eql(true) end it "should not allow a hash" do lambda { @resource.send(:gid, { :aj => "is freakin awesome" }) }.should raise_error(ArgumentError) end describe "when it has members" do before do @resource.group_name("pokemon") @resource.members(["blastoise", "pikachu"]) end it "describes its state" do state = @resource.state state[:members].should eql(["blastoise", "pikachu"]) end it "returns the group name as its identity" do @resource.identity.should == "pokemon" end end end chef-11.8.2/spec/unit/resource/conditional_action_not_nothing_spec.rb0000644000004100000410000000255312254362222026112 0ustar www-datawww-data# # Author:: Xabier de Zuazo () # Copyright:: Copyright (c) 2013 Onddo Labs, SL. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::ConditionalActionNotNothing do describe "after running a :nothing action" do before do @action = :nothing @conditional = Chef::Resource::ConditionalActionNotNothing.new(@action) end it "indicates that resource convergence should not continue" do @conditional.continue?.should be_false end end describe "after running an action different to :nothing" do before do @action = :something @conditional = Chef::Resource::ConditionalActionNotNothing.new(@action) end it "indicates that resource convergence should continue" do @conditional.continue?.should be_true end end end chef-11.8.2/spec/unit/resource/bash_spec.rb0000644000004100000410000000224412254362222020556 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Bash do before(:each) do @resource = Chef::Resource::Bash.new("fakey_fakerton") end it "should create a new Chef::Resource::Bash" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::Bash) end it "should have a resource name of :bash" do @resource.resource_name.should eql(:bash) end it "should have an interpreter of bash" do @resource.interpreter.should eql("bash") end end chef-11.8.2/spec/unit/resource/cron_spec.rb0000644000004100000410000001211312254362222020576 0ustar www-datawww-data# # Author:: Bryan McLellan (btm@loftninjas.org) # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2009 Bryan McLellan # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Cron do before(:each) do @resource = Chef::Resource::Cron.new("cronify") end it "should create a new Chef::Resource::Cron" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::Cron) end it "should have a name" do @resource.name.should eql("cronify") end it "should have a default action of 'create'" do @resource.action.should eql(:create) end it "should accept create or delete for action" do lambda { @resource.action :create }.should_not raise_error(ArgumentError) lambda { @resource.action :delete }.should_not raise_error(ArgumentError) lambda { @resource.action :lolcat }.should raise_error(ArgumentError) end it "should allow you to set a command" do @resource.command "/bin/true" @resource.command.should eql("/bin/true") end it "should allow you to set a user" do @resource.user "daemon" @resource.user.should eql("daemon") end it "should allow you to specify the minute" do @resource.minute "30" @resource.minute.should eql("30") end it "should allow you to specify the hour" do @resource.hour "6" @resource.hour.should eql("6") end it "should allow you to specify the day" do @resource.day "10" @resource.day.should eql("10") end it "should allow you to specify the month" do @resource.month "10" @resource.month.should eql("10") end it "should allow you to specify the weekday" do @resource.weekday "2" @resource.weekday.should eql("2") end it "should allow you to specify the mailto variable" do @resource.mailto "test@example.com" @resource.mailto.should eql("test@example.com") end it "should allow you to specify the path" do @resource.path "/usr/bin:/usr/sbin" @resource.path.should eql("/usr/bin:/usr/sbin") end it "should allow you to specify the home directory" do @resource.home "/root" @resource.home.should eql("/root") end it "should allow you to specify the shell to run the command with" do @resource.shell "/bin/zsh" @resource.shell.should eql("/bin/zsh") end it "should allow you to specify environment variables hash" do env = {"TEST" => "LOL"} @resource.environment env @resource.environment.should eql(env) end it "should allow * for all time and date values" do [ "minute", "hour", "day", "month", "weekday" ].each do |x| @resource.send(x, "*").should eql("*") end end it "should allow ranges for all time and date values" do [ "minute", "hour", "day", "month", "weekday" ].each do |x| @resource.send(x, "1-2,5").should eql("1-2,5") end end it "should have a default value of * for all time and date values" do [ "minute", "hour", "day", "month", "weekday" ].each do |x| @resource.send(x).should eql("*") end end it "should have a default value of root for the user" do @resource.user.should eql("root") end it "should reject any minute over 59" do lambda { @resource.minute "60" }.should raise_error(RangeError) end it "should reject any hour over 23" do lambda { @resource.hour "24" }.should raise_error(RangeError) end it "should reject any day over 31" do lambda { @resource.day "32" }.should raise_error(RangeError) end it "should reject any month over 12" do lambda { @resource.month "13" }.should raise_error(RangeError) end it "should reject any weekday over 7" do lambda { @resource.weekday "8" }.should raise_error(RangeError) end it "should convert integer schedule values to a string" do [ "minute", "hour", "day", "month", "weekday" ].each do |x| @resource.send(x, 5).should eql("5") end end describe "when it has a time (minute, hour, day, month, weeekend) and user" do before do @resource.command("tackle") @resource.minute("1") @resource.hour("2") @resource.day("3") @resource.month("4") @resource.weekday("5") @resource.user("root") end it "describes the state" do state = @resource.state state[:minute].should == "1" state[:hour].should == "2" state[:day].should == "3" state[:month].should == "4" state[:weekday].should == "5" state[:user].should == "root" end it "returns the command as its identity" do @resource.identity.should == "tackle" end end end chef-11.8.2/spec/unit/resource/service_spec.rb0000644000004100000410000001254312254362222021304 0ustar www-datawww-data# # Author:: AJ Christensen () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Service do before(:each) do @resource = Chef::Resource::Service.new("chef") end it "should create a new Chef::Resource::Service" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::Service) end it "should set the service_name to the first argument to new" do @resource.service_name.should eql("chef") end it "should set the pattern to be the service name by default" do @resource.pattern.should eql("chef") end it "should accept a string for the service name" do @resource.service_name "something" @resource.service_name.should eql("something") end it "should accept a string for the service pattern" do @resource.pattern ".*" @resource.pattern.should eql(".*") end it "should not accept a regexp for the service pattern" do lambda { @resource.pattern /.*/ }.should raise_error(ArgumentError) end it "should accept a string for the service start command" do @resource.start_command "/etc/init.d/chef start" @resource.start_command.should eql("/etc/init.d/chef start") end it "should not accept a regexp for the service start command" do lambda { @resource.start_command /.*/ }.should raise_error(ArgumentError) end it "should accept a string for the service stop command" do @resource.stop_command "/etc/init.d/chef stop" @resource.stop_command.should eql("/etc/init.d/chef stop") end it "should not accept a regexp for the service stop command" do lambda { @resource.stop_command /.*/ }.should raise_error(ArgumentError) end it "should accept a string for the service status command" do @resource.status_command "/etc/init.d/chef status" @resource.status_command.should eql("/etc/init.d/chef status") end it "should not accept a regexp for the service status command" do lambda { @resource.status_command /.*/ }.should raise_error(ArgumentError) end it "should accept a string for the service restart command" do @resource.restart_command "/etc/init.d/chef restart" @resource.restart_command.should eql("/etc/init.d/chef restart") end it "should not accept a regexp for the service restart command" do lambda { @resource.restart_command /.*/ }.should raise_error(ArgumentError) end it "should accept a string for the service reload command" do @resource.reload_command "/etc/init.d/chef reload" @resource.reload_command.should eql("/etc/init.d/chef reload") end it "should not accept a regexp for the service reload command" do lambda { @resource.reload_command /.*/ }.should raise_error(ArgumentError) end it "should accept a string for the service init command" do @resource.init_command "/etc/init.d/chef" @resource.init_command.should eql("/etc/init.d/chef") end it "should not accept a regexp for the service init command" do lambda { @resource.init_command /.*/ }.should raise_error(ArgumentError) end %w{enabled running}.each do |attrib| it "should accept true for #{attrib}" do @resource.send(attrib, true) @resource.send(attrib).should eql(true) end it "should accept false for #{attrib}" do @resource.send(attrib, false) @resource.send(attrib).should eql(false) end it "should not accept a string for #{attrib}" do lambda { @resource.send(attrib, "poop") }.should raise_error(ArgumentError) end it "should default all the feature support to false" do support_hash = { :status => false, :restart => false, :reload=> false } @resource.supports.should == support_hash end it "should allow you to set what features this resource supports as a array" do support_array = [ :status, :restart ] support_hash = { :status => true, :restart => true, :reload => false } @resource.supports(support_array) @resource.supports.should == support_hash end it "should allow you to set what features this resource supports as a hash" do support_hash = { :status => true, :restart => true, :reload => false } @resource.supports(support_hash) @resource.supports.should == support_hash end end describe "when it has pattern and supports" do before do @resource.service_name("superfriend") @resource.enabled(true) @resource.running(false) end it "describes its state" do state = @resource.state state[:enabled].should eql(true) state[:running].should eql(false) end it "returns the service name as its identity" do @resource.identity.should == "superfriend" end end end chef-11.8.2/spec/unit/resource/ips_package_spec.rb0000644000004100000410000000251112254362222022104 0ustar www-datawww-data# # Author:: Bryan McLellan # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::IpsPackage, "initialize" do before(:each) do @resource = Chef::Resource::IpsPackage.new("crypto/gnupg") end it "should return a Chef::Resource::IpsPackage" do @resource.should be_a_kind_of(Chef::Resource::IpsPackage) end it "should set the resource_name to :ips_package" do @resource.resource_name.should eql(:ips_package) end it "should set the provider to Chef::Provider::Package::Ips" do @resource.provider.should eql(Chef::Provider::Package::Ips) end it "should support accept_license" do @resource.accept_license(true) @resource.accept_license.should eql(true) end end chef-11.8.2/spec/unit/resource/macports_package_spec.rb0000644000004100000410000000235512254362222023147 0ustar www-datawww-data# # Author:: David Balatero () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::MacportsPackage, "initialize" do before(:each) do @resource = Chef::Resource::MacportsPackage.new("foo") end it "should return a Chef::Resource::MacportsPackage" do @resource.should be_a_kind_of(Chef::Resource::MacportsPackage) end it "should set the resource_name to :macports_package" do @resource.resource_name.should eql(:macports_package) end it "should set the provider to Chef::Provider::Package::Macports" do @resource.provider.should eql(Chef::Provider::Package::Macports) end end chef-11.8.2/spec/unit/resource/subversion_spec.rb0000644000004100000410000000330212254362222022034 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Subversion do before do @svn = Chef::Resource::Subversion.new("ohai, svn project!") end it "is a subclass of Resource::Scm" do @svn.should be_an_instance_of(Chef::Resource::Subversion) @svn.should be_a_kind_of(Chef::Resource::Scm) end it "uses the subversion provider" do @svn.provider.should eql(Chef::Provider::Subversion) end it "allows the force_export action" do @svn.allowed_actions.should include(:force_export) end it "sets svn info arguments to --no-auth-cache by default" do @svn.svn_info_args.should == '--no-auth-cache' end it "resets svn info arguments to nil when given false in the setter" do @svn.svn_info_args(false) @svn.svn_info_args.should be_nil end it "sets svn arguments to --no-auth-cache by default" do @svn.svn_arguments.should == '--no-auth-cache' end it "resets svn arguments to nil when given false in the setter" do @svn.svn_arguments(false) @svn.svn_arguments.should be_nil end end chef-11.8.2/spec/unit/resource/link_spec.rb0000644000004100000410000000744512254362222020606 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Link do before(:each) do Chef::Resource::Link.any_instance.should_receive(:verify_links_supported!).and_return(true) @resource = Chef::Resource::Link.new("fakey_fakerton") end it "should create a new Chef::Resource::Link" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::Link) end it "should have a name" do @resource.name.should eql("fakey_fakerton") end it "should have a default action of 'create'" do @resource.action.should eql(:create) end { :create => false, :delete => false, :blues => true }.each do |action,bad_value| it "should #{bad_value ? 'not' : ''} accept #{action.to_s}" do if bad_value lambda { @resource.action action }.should raise_error(ArgumentError) else lambda { @resource.action action }.should_not raise_error(ArgumentError) end end end it "should use the object name as the target_file by default" do @resource.target_file.should eql("fakey_fakerton") end it "should accept a string as the link source via 'to'" do lambda { @resource.to "/tmp" }.should_not raise_error(ArgumentError) end it "should not accept a Hash for the link source via 'to'" do lambda { @resource.to Hash.new }.should raise_error(ArgumentError) end it "should allow you to set a link source via 'to'" do @resource.to "/tmp/foo" @resource.to.should eql("/tmp/foo") end it "should allow you to specify the link type" do @resource.link_type "symbolic" @resource.link_type.should eql(:symbolic) end it "should default to a symbolic link" do @resource.link_type.should eql(:symbolic) end it "should accept a hard link_type" do @resource.link_type :hard @resource.link_type.should eql(:hard) end it "should reject any other link_type but :hard and :symbolic" do lambda { @resource.link_type "x-men" }.should raise_error(ArgumentError) end it "should accept a group name or id for group" do lambda { @resource.group "root" }.should_not raise_error(ArgumentError) lambda { @resource.group 123 }.should_not raise_error(ArgumentError) lambda { @resource.group "root*goo" }.should raise_error(ArgumentError) end it "should accept a user name or id for owner" do lambda { @resource.owner "root" }.should_not raise_error(ArgumentError) lambda { @resource.owner 123 }.should_not raise_error(ArgumentError) lambda { @resource.owner "root*goo" }.should raise_error(ArgumentError) end describe "when it has to, link_type, owner, and group" do before do @resource.target_file("/var/target.tar") @resource.to("/to/dir/file.tar") @resource.link_type(:symbolic) @resource.owner("root") @resource.group("0664") end it "describes its state" do state = @resource.state state[:to].should == "/to/dir/file.tar" state[:owner].should == "root" state[:group].should == "0664" end it "returns the target file as its identity" do @resource.identity.should == "/var/target.tar" end end end chef-11.8.2/spec/unit/resource/gem_package_spec.rb0000644000004100000410000000301012254362222022054 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::GemPackage, "initialize" do before(:each) do @resource = Chef::Resource::GemPackage.new("foo") end it "should return a Chef::Resource::GemPackage" do @resource.should be_a_kind_of(Chef::Resource::GemPackage) end it "should set the resource_name to :gem_package" do @resource.resource_name.should eql(:gem_package) end it "should set the provider to Chef::Provider::Package::Rubygems" do @resource.provider.should eql(Chef::Provider::Package::Rubygems) end end describe Chef::Resource::GemPackage, "gem_binary" do before(:each) do @resource = Chef::Resource::GemPackage.new("foo") end it "should set the gem_binary variable to whatever is passed in" do @resource.gem_binary("/opt/local/bin/gem") @resource.gem_binary.should eql("/opt/local/bin/gem") end end chef-11.8.2/spec/unit/resource/execute_spec.rb0000644000004100000410000000170012254362222021277 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Execute do let(:resource_instance_name) { "some command" } let(:execute_resource) { Chef::Resource::Execute.new(resource_instance_name) } it_behaves_like "an execute resource" end chef-11.8.2/spec/unit/resource/mount_spec.rb0000644000004100000410000001307312254362222021005 0ustar www-datawww-data# # Author:: Joshua Timberman () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2009 Opscode, Inc # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Mount do before(:each) do @resource = Chef::Resource::Mount.new("filesystem") end it "should create a new Chef::Resource::Mount" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::Mount) end it "should have a name" do @resource.name.should eql("filesystem") end it "should set mount_point to the name" do @resource.mount_point.should eql("filesystem") end it "should have a default action of mount" do @resource.action.should eql(:mount) end it "should accept mount, umount and remount as actions" do lambda { @resource.action :mount }.should_not raise_error(ArgumentError) lambda { @resource.action :umount }.should_not raise_error(ArgumentError) lambda { @resource.action :remount }.should_not raise_error(ArgumentError) lambda { @resource.action :brooklyn }.should raise_error(ArgumentError) end it "should allow you to set the device attribute" do @resource.device "/dev/sdb3" @resource.device.should eql("/dev/sdb3") end it "should allow you to set the fstype attribute" do @resource.fstype "nfs" @resource.fstype.should eql("nfs") end it "should allow you to set the dump attribute" do @resource.dump 1 @resource.dump.should eql(1) end it "should allow you to set the pass attribute" do @resource.pass 1 @resource.pass.should eql(1) end it "should set the options attribute to defaults" do @resource.options.should eql(["defaults"]) end it "should allow options to be sent as a string, and convert to array" do @resource.options "rw,noexec" @resource.options.should be_a_kind_of(Array) end it "should allow options attribute as an array" do @resource.options ["ro", "nosuid"] @resource.options.should be_a_kind_of(Array) end it "should accept true for mounted" do @resource.mounted(true) @resource.mounted.should eql(true) end it "should accept false for mounted" do @resource.mounted(false) @resource.mounted.should eql(false) end it "should set mounted to false by default" do @resource.mounted.should eql(false) end it "should not accept a string for mounted" do lambda { @resource.mounted("poop") }.should raise_error(ArgumentError) end it "should accept true for enabled" do @resource.enabled(true) @resource.enabled.should eql(true) end it "should accept false for enabled" do @resource.enabled(false) @resource.enabled.should eql(false) end it "should set enabled to false by default" do @resource.enabled.should eql(false) end it "should not accept a string for enabled" do lambda { @resource.enabled("poop") }.should raise_error(ArgumentError) end it "should default all feature support to false" do support_hash = { :remount => false } @resource.supports.should == support_hash end it "should allow you to set feature support as an array" do support_array = [ :remount ] support_hash = { :remount => true } @resource.supports(support_array) @resource.supports.should == support_hash end it "should allow you to set feature support as a hash" do support_hash = { :remount => true } @resource.supports(support_hash) @resource.supports.should == support_hash end it "should allow you to set username" do @resource.username("Administrator") @resource.username.should == "Administrator" end it "should allow you to set password" do @resource.password("Jetstream123!") @resource.password.should == "Jetstream123!" end it "should allow you to set domain" do @resource.domain("TEST_DOMAIN") @resource.domain.should == "TEST_DOMAIN" end describe "when it has mount point, device type, and fstype" do before do @resource.device("charmander") @resource.mount_point("123.456") @resource.device_type(:device) @resource.fstype("ranked") end it "describes its state" do state = @resource.state state[:mount_point].should == "123.456" state[:device_type].should eql(:device) state[:fstype].should == "ranked" end it "returns the device as its identity" do @resource.identity.should == "charmander" end end describe "when it has username, password and domain" do before do @resource.mount_point("T:") @resource.device("charmander") @resource.username("Administrator") @resource.password("Jetstream123!") @resource.domain("TEST_DOMAIN") end it "describes its state" do state = @resource.state puts state state[:mount_point].should == "T:" state[:username].should == "Administrator" state[:password].should == "Jetstream123!" state[:domain].should == "TEST_DOMAIN" state[:device_type].should eql(:device) state[:fstype].should == "auto" end end end chef-11.8.2/spec/unit/resource/chef_gem_spec.rb0000644000004100000410000000301012254362222021366 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Bryan McLellan # Copyright:: Copyright (c) 2008, 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::ChefGem, "initialize" do before(:each) do @resource = Chef::Resource::ChefGem.new("foo") end it "should return a Chef::Resource::ChefGem" do @resource.should be_a_kind_of(Chef::Resource::ChefGem) end it "should set the resource_name to :chef_gem" do @resource.resource_name.should eql(:chef_gem) end it "should set the provider to Chef::Provider::Package::Rubygems" do @resource.provider.should eql(Chef::Provider::Package::Rubygems) end end describe Chef::Resource::ChefGem, "gem_binary" do before(:each) do @resource = Chef::Resource::ChefGem.new("foo") end it "should raise an exception when gem_binary is set" do lambda { @resource.gem_binary("/lol/cats/gem") }.should raise_error(ArgumentError) end end chef-11.8.2/spec/unit/resource/ruby_spec.rb0000644000004100000410000000224412254362222020622 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Ruby do before(:each) do @resource = Chef::Resource::Ruby.new("fakey_fakerton") end it "should create a new Chef::Resource::Ruby" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::Ruby) end it "should have a resource name of :ruby" do @resource.resource_name.should eql(:ruby) end it "should have an interpreter of ruby" do @resource.interpreter.should eql("ruby") end end chef-11.8.2/spec/unit/resource/env_spec.rb0000644000004100000410000000470212254362222020432 0ustar www-datawww-data# # Author:: Doug MacEachern () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2010 VMware, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Env do before(:each) do @resource = Chef::Resource::Env.new("FOO") end it "should create a new Chef::Resource::Env" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::Env) end it "should have a name" do @resource.name.should eql("FOO") end it "should have a default action of 'create'" do @resource.action.should eql(:create) end { :create => false, :delete => false, :modify => false, :flibber => true }.each do |action,bad_value| it "should #{bad_value ? 'not' : ''} accept #{action.to_s}" do if bad_value lambda { @resource.action action }.should raise_error(ArgumentError) else lambda { @resource.action action }.should_not raise_error(ArgumentError) end end end it "should use the object name as the key_name by default" do @resource.key_name.should eql("FOO") end it "should accept a string as the env value via 'value'" do lambda { @resource.value "bar" }.should_not raise_error(ArgumentError) end it "should not accept a Hash for the env value via 'to'" do lambda { @resource.value Hash.new }.should raise_error(ArgumentError) end it "should allow you to set an env value via 'to'" do @resource.value "bar" @resource.value.should eql("bar") end describe "when it has key name and value" do before do @resource.key_name("charmander") @resource.value("level7") @resource.delim("hi") end it "describes its state" do state = @resource.state state[:value].should == "level7" end it "returns the key name as its identity" do @resource.identity.should == "charmander" end end end chef-11.8.2/spec/unit/resource/script_spec.rb0000644000004100000410000000270212254362222021144 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Script do let(:resource_instance_name) { "fakey_fakerton" } let(:script_resource) { Chef::Resource::Script.new(resource_instance_name) } let(:resource_name) { :script } it "should accept a string for the interpreter" do script_resource.interpreter "naaaaNaNaNaaNaaNaaNaa" script_resource.interpreter.should eql("naaaaNaNaNaaNaaNaaNaa") end describe "when it has interpreter and flags" do before do script_resource.command("grep") script_resource.interpreter("gcc") script_resource.flags("-al") end it "returns the command as its identity" do script_resource.identity.should == "grep" end end it_behaves_like "a script resource" end chef-11.8.2/spec/unit/resource/ifconfig_spec.rb0000644000004100000410000000721612254362222021431 0ustar www-datawww-data# # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2009 Joe Williams # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Ifconfig do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @resource = Chef::Resource::Ifconfig.new("fakey_fakerton", @run_context) end describe "when it has target, hardware address, inet address, and a mask" do before do @resource.device("charmander") @resource.target("team_rocket") @resource.hwaddr("11.2223.223") @resource.inet_addr("434.2343.23") @resource.mask("255.255.545") end it "describes its state" do state = @resource.state state[:inet_addr].should == "434.2343.23" state[:mask].should == "255.255.545" end it "returns the device as its identity" do @resource.identity.should == "charmander" end end shared_examples "being a platform using the default ifconfig provider" do |platform, version| before do @node.automatic_attrs[:platform] = platform @node.automatic_attrs[:platform_version] = version end it "should use an ordinary Provider::Ifconfig as a provider for #{platform} #{version}" do @resource.provider_for_action(:add).should be_a_kind_of(Chef::Provider::Ifconfig) @resource.provider_for_action(:add).should_not be_a_kind_of(Chef::Provider::Ifconfig::Debian) @resource.provider_for_action(:add).should_not be_a_kind_of(Chef::Provider::Ifconfig::Redhat) end end shared_examples "being a platform based on RedHat" do |platform, version| before do @node.automatic_attrs[:platform] = platform @node.automatic_attrs[:platform_version] = version end it "should use an Provider::Ifconfig::Redhat as a provider for #{platform} #{version}" do @resource.provider_for_action(:add).should be_a_kind_of(Chef::Provider::Ifconfig::Redhat) end end shared_examples "being a platform based on a recent Debian" do |platform, version| before do @node.automatic_attrs[:platform] = platform @node.automatic_attrs[:platform_version] = version end it "should use an Ifconfig::Debian as a provider for #{platform} #{version}" do @resource.provider_for_action(:add).should be_a_kind_of(Chef::Provider::Ifconfig::Debian) end end describe "when it is a RedHat platform" do it_should_behave_like "being a platform based on RedHat", "redhat", "4.0" end describe "when it is an old Debian platform" do it_should_behave_like "being a platform using the default ifconfig provider", "debian", "6.0" end describe "when it is a new Debian platform" do it_should_behave_like "being a platform based on a recent Debian", "debian", "7.0" end describe "when it is an old Ubuntu platform" do it_should_behave_like "being a platform using the default ifconfig provider", "ubuntu", "11.04" end describe "when it is a new Ubuntu platform" do it_should_behave_like "being a platform based on a recent Debian", "ubuntu", "11.10" end end chef-11.8.2/spec/unit/resource/rpm_package_spec.rb0000644000004100000410000000231112254362222022105 0ustar www-datawww-data# # Author:: Thomas Bishop () # Copyright:: Copyright (c) 2010 Thomas Bishop # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::RpmPackage, "initialize" do before(:each) do @resource = Chef::Resource::RpmPackage.new("foo") end it "should return a Chef::Resource::RpmPackage" do @resource.should be_a_kind_of(Chef::Resource::RpmPackage) end it "should set the resource_name to :rpm_package" do @resource.resource_name.should eql(:rpm_package) end it "should set the provider to Chef::Provider::Package::Rpm" do @resource.provider.should eql(Chef::Provider::Package::Rpm) end end chef-11.8.2/spec/unit/resource/scm_spec.rb0000644000004100000410000001172112254362222020423 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Scm do before(:each) do @resource = Chef::Resource::Scm.new("my awesome app") end it "should be a SCM resource" do @resource.should be_a_kind_of(Chef::Resource::Scm) end it "supports :checkout, :export, :sync, :diff, and :log actions" do @resource.allowed_actions.should include(:checkout) @resource.allowed_actions.should include(:export) @resource.allowed_actions.should include(:sync) @resource.allowed_actions.should include(:diff) @resource.allowed_actions.should include(:log) end it "takes the destination path as a string" do @resource.destination "/path/to/deploy/dir" @resource.destination.should eql("/path/to/deploy/dir") end it "takes a string for the repository URL" do @resource.repository "git://github.com/opscode/chef.git" @resource.repository.should eql("git://github.com/opscode/chef.git") end it "takes a string for the revision" do @resource.revision "abcdef" @resource.revision.should eql("abcdef") end it "defaults to the ``HEAD'' revision" do @resource.revision.should eql("HEAD") end it "takes a string for the user to run as" do @resource.user "dr_deploy" @resource.user.should eql("dr_deploy") end it "also takes an integer for the user to run as" do @resource.user 0 @resource.user.should eql(0) end it "takes a string for the group to run as, defaulting to nil" do @resource.group.should be_nil @resource.group "opsdevs" @resource.group.should == "opsdevs" end it "also takes an integer for the group to run as" do @resource.group 23 @resource.group.should == 23 end it "has a svn_username String attribute" do @resource.svn_username "moartestsplz" @resource.svn_username.should eql("moartestsplz") end it "has a svn_password String attribute" do @resource.svn_password "taftplz" @resource.svn_password.should eql("taftplz") end it "has a svn_arguments String attribute" do @resource.svn_arguments "--more-taft plz" @resource.svn_arguments.should eql("--more-taft plz") end it "has a svn_info_args String attribute" do @resource.svn_info_args.should be_nil @resource.svn_info_args("--no-moar-plaintext-creds yep") @resource.svn_info_args.should == "--no-moar-plaintext-creds yep" end it "takes the depth as an integer for shallow clones" do @resource.depth 5 @resource.depth.should == 5 lambda {@resource.depth "five"}.should raise_error(ArgumentError) end it "defaults to nil depth for a full clone" do @resource.depth.should be_nil end it "takes a boolean for #enable_submodules" do @resource.enable_submodules true @resource.enable_submodules.should be_true lambda {@resource.enable_submodules "lolz"}.should raise_error(ArgumentError) end it "defaults to not enabling submodules" do @resource.enable_submodules.should be_false end it "takes a string for the remote" do @resource.remote "opscode" @resource.remote.should eql("opscode") lambda {@resource.remote 1337}.should raise_error(ArgumentError) end it "defaults to ``origin'' for the remote" do @resource.remote.should == "origin" end it "takes a string for the ssh wrapper" do @resource.ssh_wrapper "with_ssh_fu" @resource.ssh_wrapper.should eql("with_ssh_fu") end it "defaults to nil for the ssh wrapper" do @resource.ssh_wrapper.should be_nil end describe "when it has a timeout attribute" do let(:ten_seconds) { 10 } before { @resource.timeout(ten_seconds) } it "stores this timeout" do @resource.timeout.should == ten_seconds end end describe "when it has no timeout attribute" do it "should have no default timeout" do @resource.timeout.should be_nil end end describe "when it has repository, revision, user, and group" do before do @resource.destination("hell") @resource.repository("apt") @resource.revision("1.2.3") @resource.user("root") @resource.group("super_adventure_club") end it "describes its state" do state = @resource.state state[:revision].should == "1.2.3" end it "returns the destination as its identity" do @resource.identity.should == "hell" end end end chef-11.8.2/spec/unit/resource/package_spec.rb0000644000004100000410000000437012254362222021236 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Package do before(:each) do @resource = Chef::Resource::Package.new("emacs") end it "should create a new Chef::Resource::Package" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::Package) end it "should set the package_name to the first argument to new" do @resource.package_name.should eql("emacs") end it "should accept a string for the package name" do @resource.package_name "something" @resource.package_name.should eql("something") end it "should accept a string for the version" do @resource.version "something" @resource.version.should eql("something") end it "should accept a string for the response file" do @resource.response_file "something" @resource.response_file.should eql("something") end it "should accept a string for the source" do @resource.source "something" @resource.source.should eql("something") end it "should accept a string for the options" do @resource.options "something" @resource.options.should eql("something") end describe "when it has a package_name and version" do before do @resource.package_name("tomcat") @resource.version("10.9.8") @resource.options("-al") end it "describes its state" do state = @resource.state state[:version].should == "10.9.8" state[:options].should == "-al" end it "returns the file path as its identity" do @resource.identity.should == "tomcat" end end end chef-11.8.2/spec/unit/resource/apt_package_spec.rb0000644000004100000410000000253412254362222022102 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::AptPackage, "initialize" do before(:each) do @resource = Chef::Resource::AptPackage.new("foo") end it "should return a Chef::Resource::AptPackage" do @resource.should be_a_kind_of(Chef::Resource::AptPackage) end it "should set the resource_name to :apt_package" do @resource.resource_name.should eql(:apt_package) end it "should set the provider to Chef::Provider::Package::Apt" do @resource.provider.should eql(Chef::Provider::Package::Apt) end it "should support default_release" do @resource.default_release("lenny-backports") @resource.default_release.should eql("lenny-backports") end end chef-11.8.2/spec/unit/resource/cookbook_file_spec.rb0000644000004100000410000000567512254362222022461 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2010 Opscode, Inc. #p License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::CookbookFile do before do @cookbook_file = Chef::Resource::CookbookFile.new('sourcecode_tarball.tgz') end it "uses the name parameter for the source parameter" do @cookbook_file.name.should == 'sourcecode_tarball.tgz' end it "has a source parameter" do @cookbook_file.name('config_file.conf') @cookbook_file.name.should == 'config_file.conf' end it "defaults to a nil cookbook parameter (current cookbook will be used)" do @cookbook_file.cookbook.should be_nil end it "has a cookbook parameter" do @cookbook_file.cookbook("munin") @cookbook_file.cookbook.should == 'munin' end it "sets the provider to Chef::Provider::CookbookFile" do @cookbook_file.provider.should == Chef::Provider::CookbookFile end describe "when it has a backup number, group, mode, owner, source, checksum, and cookbook on nix or path, rights, deny_rights, checksum on windows" do before do if Chef::Platform.windows? @cookbook_file.path("C:/temp/origin/file.txt") @cookbook_file.rights(:read, "Everyone") @cookbook_file.deny_rights(:full_control, "Clumsy_Sam") else @cookbook_file.path("/tmp/origin/file.txt") @cookbook_file.group("wheel") @cookbook_file.mode("0664") @cookbook_file.owner("root") @cookbook_file.source("/tmp/foo.txt") @cookbook_file.cookbook("/tmp/cookbooks/cooked.rb") end @cookbook_file.checksum("1" * 64) end it "describes the state" do state = @cookbook_file.state if Chef::Platform.windows? puts state state[:rights].should == [{:permissions => :read, :principals => "Everyone"}] state[:deny_rights].should == [{:permissions => :full_control, :principals => "Clumsy_Sam"}] else state[:group].should == "wheel" state[:mode].should == "0664" state[:owner].should == "root" end state[:checksum].should == "1" * 64 end it "returns the path as its identity" do if Chef::Platform.windows? @cookbook_file.identity.should == "C:/temp/origin/file.txt" else @cookbook_file.identity.should == "/tmp/origin/file.txt" end end end end chef-11.8.2/spec/unit/resource/user_spec.rb0000644000004100000410000000727712254362222020632 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::User, "initialize" do before(:each) do @resource = Chef::Resource::User.new("adam") end it "should create a new Chef::Resource::User" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::User) end it "should set the resource_name to :user" do @resource.resource_name.should eql(:user) end it "should set the username equal to the argument to initialize" do @resource.username.should eql("adam") end %w{comment uid gid home shell password}.each do |attrib| it "should set #{attrib} to nil" do @resource.send(attrib).should eql(nil) end end it "should set action to :create" do @resource.action.should eql(:create) end it "should set supports[:manage_home] to false" do @resource.supports[:manage_home].should eql(false) end it "should set supports[:non_unique] to false" do @resource.supports[:non_unique].should eql(false) end %w{create remove modify manage lock unlock}.each do |action| it "should allow action #{action}" do @resource.allowed_actions.detect { |a| a == action.to_sym }.should eql(action.to_sym) end end it "should accept domain users (@ or \ separator) on non-windows" do lambda { @resource.username "domain\@user" }.should_not raise_error(ArgumentError) @resource.username.should == "domain\@user" lambda { @resource.username "domain\\user" }.should_not raise_error(ArgumentError) @resource.username.should == "domain\\user" end end %w{username comment home shell password}.each do |attrib| describe Chef::Resource::User, attrib do before(:each) do @resource = Chef::Resource::User.new("adam") end it "should allow a string" do @resource.send(attrib, "adam") @resource.send(attrib).should eql("adam") end it "should not allow a hash" do lambda { @resource.send(attrib, { :woot => "i found it" }) }.should raise_error(ArgumentError) end end end %w{uid gid}.each do |attrib| describe Chef::Resource::User, attrib do before(:each) do @resource = Chef::Resource::User.new("adam") end it "should allow a string" do @resource.send(attrib, "100") @resource.send(attrib).should eql("100") end it "should allow an integer" do @resource.send(attrib, 100) @resource.send(attrib).should eql(100) end it "should not allow a hash" do lambda { @resource.send(attrib, { :woot => "i found it" }) }.should raise_error(ArgumentError) end end describe "when it has uid, gid, and home" do before do @resource = Chef::Resource::User.new("root") @resource.uid(123) @resource.gid(456) @resource.home("/usr/local/root/") end it "describes its state" do state = @resource.state state[:uid].should == 123 state[:gid].should == 456 state[:home].should == "/usr/local/root/" end it "returns the username as its identity" do @resource.identity.should == "root" end end end chef-11.8.2/spec/unit/resource/directory_spec.rb0000644000004100000410000000523512254362222021650 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Directory do before(:each) do @resource = Chef::Resource::Directory.new("fakey_fakerton") end it "should create a new Chef::Resource::Directory" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::Directory) end it "should have a name" do @resource.name.should eql("fakey_fakerton") end it "should have a default action of 'create'" do @resource.action.should eql(:create) end it "should accept create or delete for action" do lambda { @resource.action :create }.should_not raise_error(ArgumentError) lambda { @resource.action :delete }.should_not raise_error(ArgumentError) lambda { @resource.action :blues }.should raise_error(ArgumentError) end it "should use the object name as the path by default" do @resource.path.should eql("fakey_fakerton") end it "should accept a string as the path" do lambda { @resource.path "/tmp" }.should_not raise_error(ArgumentError) @resource.path.should eql("/tmp") lambda { @resource.path Hash.new }.should raise_error(ArgumentError) end it "should allow you to have specify whether the action is recursive with true/false" do lambda { @resource.recursive true }.should_not raise_error(ArgumentError) lambda { @resource.recursive false }.should_not raise_error(ArgumentError) lambda { @resource.recursive "monkey" }.should raise_error(ArgumentError) end describe "when it has group, mode, and owner" do before do @resource.path("/tmp/foo/bar/") @resource.group("wheel") @resource.mode("0664") @resource.owner("root") end it "describes its state" do state = @resource.state state[:group].should == "wheel" state[:mode].should == "0664" state[:owner].should == "root" end it "returns the directory path as its identity" do @resource.identity.should == "/tmp/foo/bar/" end end end chef-11.8.2/spec/unit/resource/python_spec.rb0000644000004100000410000000226412254362222021164 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Python do before(:each) do @resource = Chef::Resource::Python.new("fakey_fakerton") end it "should create a new Chef::Resource::Python" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::Python) end it "should have a resource name of :python" do @resource.resource_name.should eql(:python) end it "should have an interpreter of python" do @resource.interpreter.should eql("python") end end chef-11.8.2/spec/unit/resource/freebsd_package_spec.rb0000644000004100000410000000234212254362222022725 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::FreebsdPackage, "initialize" do before(:each) do @resource = Chef::Resource::FreebsdPackage.new("foo") end it "should return a Chef::Resource::FreebsdPackage" do @resource.should be_a_kind_of(Chef::Resource::FreebsdPackage) end it "should set the resource_name to :freebsd_package" do @resource.resource_name.should eql(:freebsd_package) end it "should set the provider to Chef::Provider::Package::freebsd" do @resource.provider.should eql(Chef::Provider::Package::Freebsd) end end chef-11.8.2/spec/unit/resource/remote_directory_spec.rb0000644000004100000410000000565112254362222023225 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::RemoteDirectory do before(:each) do @resource = Chef::Resource::RemoteDirectory.new("/etc/dunk") end it "should create a new Chef::Resource::RemoteDirectory" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::RemoteDirectory) end it "should set the path to the first argument to new" do @resource.path.should eql("/etc/dunk") end it "should accept a string for the remote directory source" do @resource.source "foo" @resource.source.should eql("foo") end it "should have the basename of the remote directory resource as the default source" do @resource.source.should eql("dunk") end it "should accept a number for the remote files backup" do @resource.files_backup 1 @resource.files_backup.should eql(1) end it "should accept false for the remote files backup" do @resource.files_backup false @resource.files_backup.should eql(false) end it "should accept 3 or 4 digets for the files_mode" do @resource.files_mode 100 @resource.files_mode.should eql(100) @resource.files_mode 1000 @resource.files_mode.should eql(1000) end it "should accept a string or number for the files group" do @resource.files_group "heart" @resource.files_group.should eql("heart") @resource.files_group 1000 @resource.files_group.should eql(1000) end it "should accept a string or number for the files owner" do @resource.files_owner "heart" @resource.files_owner.should eql("heart") @resource.files_owner 1000 @resource.files_owner.should eql(1000) end describe "when it has cookbook, files owner, files mode, and source" do before do @resource.path("/var/path/") @resource.cookbook("pokemon.rb") @resource.files_owner("root") @resource.files_group("supergroup") @resource.files_mode("0664") @resource.source("/var/source/") end it "describes its state" do state = @resource.state state[:files_owner].should == "root" state[:files_group].should == "supergroup" state[:files_mode].should == "0664" end it "returns the path as its identity" do @resource.identity.should == "/var/path/" end end end chef-11.8.2/spec/unit/resource/remote_file_spec.rb0000644000004100000410000001226512254362222022137 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::RemoteFile do before(:each) do @resource = Chef::Resource::RemoteFile.new("fakey_fakerton") end describe "initialize" do it "should create a new Chef::Resource::RemoteFile" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::File) @resource.should be_a_kind_of(Chef::Resource::RemoteFile) end end it "says its provider is RemoteFile when the source is an absolute URI" do @resource.source("http://www.google.com/robots.txt") @resource.provider.should == Chef::Provider::RemoteFile Chef::Platform.find_provider(:noplatform, 'noversion', @resource).should == Chef::Provider::RemoteFile end describe "source" do it "does not have a default value for 'source'" do @resource.source.should eql([]) end it "should accept a URI for the remote file source" do @resource.source "http://opscode.com/" @resource.source.should eql([ "http://opscode.com/" ]) end it "should accept an array of URIs for the remote file source" do @resource.source([ "http://opscode.com/", "http://puppetlabs.com/" ]) @resource.source.should eql([ "http://opscode.com/", "http://puppetlabs.com/" ]) end it "should accept an multiple URIs as arguments for the remote file source" do @resource.source("http://opscode.com/", "http://puppetlabs.com/") @resource.source.should eql([ "http://opscode.com/", "http://puppetlabs.com/" ]) end it "does not accept a non-URI as the source" do lambda { @resource.source("not-a-uri") }.should raise_error(Chef::Exceptions::InvalidRemoteFileURI) end it "should raise an exception when source is an empty array" do lambda { @resource.source([]) }.should raise_error(ArgumentError) end end describe "checksum" do it "should accept a string for the checksum object" do @resource.checksum "asdf" @resource.checksum.should eql("asdf") end it "should default to nil" do @resource.checksum.should == nil end end describe "ftp_active_mode" do it "should accept a boolean for the ftp_active_mode object" do @resource.ftp_active_mode true @resource.ftp_active_mode.should be_true end it "should default to false" do @resource.ftp_active_mode.should be_false end end describe "conditional get options" do it "defaults to using etags and last modified" do @resource.use_etags.should be_true @resource.use_last_modified.should be_true end it "enable or disables etag and last modified options as a group" do @resource.use_conditional_get(false) @resource.use_etags.should be_false @resource.use_last_modified.should be_false @resource.use_conditional_get(true) @resource.use_etags.should be_true @resource.use_last_modified.should be_true end it "disables etags indivdually" do @resource.use_etags(false) @resource.use_etags.should be_false @resource.use_last_modified.should be_true end it "disables last modified individually" do @resource.use_last_modified(false) @resource.use_last_modified.should be_false @resource.use_etags.should be_true end end describe "when it has group, mode, owner, source, and checksum" do before do if Chef::Platform.windows? @resource.path("C:/temp/origin/file.txt") @resource.rights(:read, "Everyone") @resource.deny_rights(:full_control, "Clumsy_Sam") else @resource.path("/this/path/") @resource.group("pokemon") @resource.mode("0664") @resource.owner("root") end @resource.source("https://www.google.com/images/srpr/logo3w.png") @resource.checksum("1"*26) end it "describes its state" do state = @resource.state if Chef::Platform.windows? puts state state[:rights].should == [{:permissions => :read, :principals => "Everyone"}] state[:deny_rights].should == [{:permissions => :full_control, :principals => "Clumsy_Sam"}] else state[:group].should == "pokemon" state[:mode].should == "0664" state[:owner].should == "root" state[:checksum].should == "1"*26 end end it "returns the path as its identity" do if Chef::Platform.windows? @resource.identity.should == "C:/temp/origin/file.txt" else @resource.identity.should == "/this/path/" end end end end chef-11.8.2/spec/unit/resource/solaris_package_spec.rb0000644000004100000410000000364512254362222022776 0ustar www-datawww-data# # Author:: Prabhu Das () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::SolarisPackage, "initialize" do before(:each) do @resource = Chef::Resource::SolarisPackage.new("foo") end it "should return a Chef::Resource::SolarisPackage object" do @resource.should be_a_kind_of(Chef::Resource::SolarisPackage) end it "should not raise any Error when valid number of arguments are provided" do expect { Chef::Resource::SolarisPackage.new("foo") }.to_not raise_error end it "should raise ArgumentError when incorrect number of arguments are provided" do expect { Chef::Resource::SolarisPackage.new }.to raise_error(ArgumentError) end it "should set the package_name to the name provided" do @resource.package_name.should eql("foo") end it "should set the resource_name to :solaris_package" do @resource.resource_name.should eql(:solaris_package) end it "should set the run_context to the run_context provided" do @run_context = double() @run_context.stub(:node) resource = Chef::Resource::SolarisPackage.new("foo", @run_context) resource.run_context.should eql(@run_context) end it "should set the provider to Chef::Provider::Package::Solaris" do @resource.provider.should eql(Chef::Provider::Package::Solaris) end end chef-11.8.2/spec/unit/resource/portage_package_spec.rb0000644000004100000410000000244012254362222022753 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper")) describe Chef::Resource::PortagePackage, "initialize" do before(:each) do @resource = Chef::Resource::PortagePackage.new("foo") end it "should return a Chef::Resource::PortagePackage" do @resource.should be_a_kind_of(Chef::Resource::PortagePackage) end it "should set the resource_name to :portage_package" do @resource.resource_name.should eql(:portage_package) end it "should set the provider to Chef::Provider::Package::Portage" do @resource.provider.should eql(Chef::Provider::Package::Portage) end end chef-11.8.2/spec/unit/resource/breakpoint_spec.rb0000644000004100000410000000237112254362222022000 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Breakpoint do before do @breakpoint = Chef::Resource::Breakpoint.new end it "allows the action :break" do @breakpoint.allowed_actions.should include(:break) end it "defaults to the break action" do @breakpoint.action.should == "break" end it "names itself after the line number of the file where it's created" do @breakpoint.name.should match(/breakpoint_spec\.rb\:[\d]{2}\:in \`new\'$/) end it "uses the breakpoint provider" do @breakpoint.provider.should == Chef::Provider::Breakpoint end end chef-11.8.2/spec/unit/resource/log_spec.rb0000644000004100000410000000412612254362222020423 0ustar www-datawww-data# # Author:: Cary Penniman () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Log do before(:each) do @log_str = "this is my string to log" @resource = Chef::Resource::Log.new(@log_str) end it "should create a new Chef::Resource::Log" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::Log) end it "supports the :write actions" do @resource.allowed_actions.should include(:write) end it "should have a name of log" do @resource.resource_name.should == :log end it "should allow you to set a log string" do @resource.name.should == @log_str end it "should set the message to the first argument to new" do @resource.message.should == @log_str end it "should accept a string for the log message" do @resource.message "this is different" @resource.message.should == "this is different" end it "should accept a vaild level option" do @resource.level :debug @resource.level :info @resource.level :warn @resource.level :error @resource.level :fatal lambda { @resource.level :unsupported }.should raise_error(ArgumentError) end describe "when the identity is defined" do before do @resource = Chef::Resource::Log.new("ery day I'm loggin-in") end it "returns the log string as its identity" do @resource.identity.should == "ery day I'm loggin-in" end end end chef-11.8.2/spec/unit/resource/erl_call_spec.rb0000644000004100000410000000450312254362222021416 0ustar www-datawww-data# # Author:: Joe Williams () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2009 Joe Williams # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::ErlCall do before(:each) do @resource = Chef::Resource::ErlCall.new("fakey_fakerton") end it "should create a new Chef::Resource::ErlCall" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::ErlCall) end it "should have a resource name of :erl_call" do @resource.resource_name.should eql(:erl_call) end it "should have a default action of run" do @resource.action.should eql("run") end it "should accept run as an action" do lambda { @resource.action :run }.should_not raise_error(ArgumentError) end it "should allow you to set the code attribute" do @resource.code "q()." @resource.code.should eql("q().") end it "should allow you to set the cookie attribute" do @resource.cookie "nomnomnom" @resource.cookie.should eql("nomnomnom") end it "should allow you to set the distributed attribute" do @resource.distributed true @resource.distributed.should eql(true) end it "should allow you to set the name_type attribute" do @resource.name_type "sname" @resource.name_type.should eql("sname") end it "should allow you to set the node_name attribute" do @resource.node_name "chef@erlang" @resource.node_name.should eql("chef@erlang") end describe "when it has cookie and node_name" do before do @resource.code("erl-call:function()") @resource.cookie("cookie") @resource.node_name("raster") end it "returns the code as its identity" do @resource.identity.should == "erl-call:function()" end end end chef-11.8.2/spec/unit/resource/smartos_package_spec.rb0000644000004100000410000000245212254362222023005 0ustar www-datawww-data# # Author:: Thomas Bishop () # Copyright:: Copyright (c) 2010 Thomas Bishop # License:: Apache License, Version 2.0 # # 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. # require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper")) describe Chef::Resource::SmartosPackage, "initialize" do before(:each) do @resource = Chef::Resource::SmartosPackage.new("foo") end it "should return a Chef::Resource::SmartosPackage" do @resource.should be_a_kind_of(Chef::Resource::SmartosPackage) end it "should set the resource_name to :smartos_package" do @resource.resource_name.should eql(:smartos_package) end it "should set the provider to Chef::Provider::Package::SmartOS" do @resource.provider.should eql(Chef::Provider::Package::SmartOS) end end chef-11.8.2/spec/unit/resource/file_spec.rb0000644000004100000410000000771712254362222020572 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::File do before(:each) do @resource = Chef::Resource::File.new("fakey_fakerton") end it "should have a name" do @resource.name.should eql("fakey_fakerton") end it "should have a default action of 'create'" do @resource.action.should eql("create") end it "should have a default content of nil" do @resource.content.should be_nil end it "should be set to back up 5 files by default" do @resource.backup.should eql(5) end it "should only accept strings for content" do lambda { @resource.content 5 }.should raise_error(ArgumentError) lambda { @resource.content :foo }.should raise_error(ArgumentError) lambda { @resource.content "hello" => "there" }.should raise_error(ArgumentError) lambda { @resource.content "hi" }.should_not raise_error(ArgumentError) end it "should only accept false or a number for backup" do lambda { @resource.backup true }.should raise_error(ArgumentError) lambda { @resource.backup false }.should_not raise_error(ArgumentError) lambda { @resource.backup 10 }.should_not raise_error(ArgumentError) lambda { @resource.backup "blues" }.should raise_error(ArgumentError) end it "should accept a sha256 for checksum" do lambda { @resource.checksum "0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa" }.should_not raise_error(ArgumentError) lambda { @resource.checksum "monkey!" }.should raise_error(ArgumentError) end it "should accept create, delete or touch for action" do lambda { @resource.action :create }.should_not raise_error(ArgumentError) lambda { @resource.action :delete }.should_not raise_error(ArgumentError) lambda { @resource.action :touch }.should_not raise_error(ArgumentError) lambda { @resource.action :blues }.should raise_error(ArgumentError) end it "should use the object name as the path by default" do @resource.path.should eql("fakey_fakerton") end it "should accept a string as the path" do lambda { @resource.path "/tmp" }.should_not raise_error(ArgumentError) @resource.path.should eql("/tmp") lambda { @resource.path Hash.new }.should raise_error(ArgumentError) end describe "when it has a path, owner, group, mode, and checksum" do before do @resource.path("/tmp/foo.txt") @resource.owner("root") @resource.group("wheel") @resource.mode("0644") @resource.checksum("1" * 64) end context "on unix", :unix_only do it "describes its state" do state = @resource.state state[:owner].should == "root" state[:group].should == "wheel" state[:mode].should == "0644" state[:checksum].should == "1" * 64 end end it "returns the file path as its identity" do @resource.identity.should == "/tmp/foo.txt" end end describe "when access controls are set on windows", :windows_only => true do before do @resource.rights :read, "Everyone" @resource.rights :full_control, "DOMAIN\User" end it "describes its state including windows ACL attributes" do state = @resource.state state[:rights].should == [ {:permissions => :read, :principals => "Everyone"}, {:permissions => :full_control, :principals => "DOMAIN\User"} ] end end end chef-11.8.2/spec/unit/resource/dpkg_package_spec.rb0000644000004100000410000000230712254362222022241 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::DpkgPackage, "initialize" do before(:each) do @resource = Chef::Resource::DpkgPackage.new("foo") end it "should return a Chef::Resource::DpkgPackage" do @resource.should be_a_kind_of(Chef::Resource::DpkgPackage) end it "should set the resource_name to :dpkg_package" do @resource.resource_name.should eql(:dpkg_package) end it "should set the provider to Chef::Provider::Package::Dpkg" do @resource.provider.should eql(Chef::Provider::Package::Dpkg) end end chef-11.8.2/spec/unit/resource/timestamped_deploy_spec.rb0000644000004100000410000000166512254362222023537 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 Daniel DeLeo # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::TimestampedDeploy do it "defaults to the TimestampedDeploy provider" do @resource = Chef::Resource::TimestampedDeploy.new("stuff") @resource.provider.should == Chef::Provider::Deploy::Timestamped end end chef-11.8.2/spec/unit/resource/mdadm_spec.rb0000644000004100000410000000571212254362222020726 0ustar www-datawww-data# # Author:: Joe Williams () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2009 Joe Williams # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Mdadm do before(:each) do @resource = Chef::Resource::Mdadm.new("fakey_fakerton") end it "should create a new Chef::Resource::Mdadm" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::Mdadm) end it "should have a resource name of :mdadm" do @resource.resource_name.should eql(:mdadm) end it "should have a default action of create" do @resource.action.should eql(:create) end it "should accept create, assemble, stop as actions" do lambda { @resource.action :create }.should_not raise_error(ArgumentError) lambda { @resource.action :assemble }.should_not raise_error(ArgumentError) lambda { @resource.action :stop }.should_not raise_error(ArgumentError) end it "should allow you to set the raid_device attribute" do @resource.raid_device "/dev/md3" @resource.raid_device.should eql("/dev/md3") end it "should allow you to set the chunk attribute" do @resource.chunk 256 @resource.chunk.should eql(256) end it "should allow you to set the level attribute" do @resource.level 1 @resource.level.should eql(1) end it "should allow you to set the metadata attribute" do @resource.metadata "1.2" @resource.metadata.should eql("1.2") end it "should allow you to set the bitmap attribute" do @resource.metadata "internal" @resource.metadata.should eql("internal") end it "should allow you to set the devices attribute" do @resource.devices ["/dev/sda", "/dev/sdb"] @resource.devices.should eql(["/dev/sda", "/dev/sdb"]) end it "should allow you to set the exists attribute" do @resource.exists true @resource.exists.should eql(true) end describe "when it has devices, level, and chunk" do before do @resource.raid_device("raider") @resource.devices(["device1", "device2"]) @resource.level(1) @resource.chunk(42) end it "describes its state" do state = @resource.state state[:devices].should eql(["device1", "device2"]) state[:level].should == 1 state[:chunk].should == 42 end it "returns the raid device as its identity" do @resource.identity.should == "raider" end end end chef-11.8.2/spec/unit/resource/easy_install_package_spec.rb0000644000004100000410000000323012254362222023777 0ustar www-datawww-data# # Author:: Joe Williams () # Copyright:: Copyright (c) 2009 Joe Williams # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::EasyInstallPackage, "initialize" do before(:each) do @resource = Chef::Resource::EasyInstallPackage.new("foo") end it "should create a new Chef::Resource::EasyInstallPackage" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::EasyInstallPackage) end it "should return a Chef::Resource::EasyInstallPackage" do @resource.should be_a_kind_of(Chef::Resource::EasyInstallPackage) end it "should set the resource_name to :easy_install_package" do @resource.resource_name.should eql(:easy_install_package) end it "should set the provider to Chef::Provider::Package::EasyInstall" do @resource.provider.should eql(Chef::Provider::Package::EasyInstall) end it "should allow you to set the easy_install_binary attribute" do @resource.easy_install_binary "/opt/local/bin/easy_install" @resource.easy_install_binary.should eql("/opt/local/bin/easy_install") end end chef-11.8.2/spec/unit/resource/deploy_spec.rb0000644000004100000410000002353012254362222021136 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Deploy do class << self def resource_has_a_string_attribute(attr_name) it "has a String attribute for #{attr_name.to_s}" do @resource.send(attr_name, "this is a string") @resource.send(attr_name).should eql("this is a string") lambda {@resource.send(attr_name, 8675309)}.should raise_error(ArgumentError) end end def resource_has_a_boolean_attribute(attr_name, opts={:defaults_to=>false}) it "has a Boolean attribute for #{attr_name.to_s}" do @resource.send(attr_name).should eql(opts[:defaults_to]) @resource.send(attr_name, !opts[:defaults_to]) @resource.send(attr_name).should eql( !opts[:defaults_to] ) end end def resource_has_a_callback_attribute(attr_name) it "has a Callback attribute #{attr_name}" do callback_block = lambda { :noop } lambda {@resource.send(attr_name, &callback_block)}.should_not raise_error @resource.send(attr_name).should == callback_block callback_file = "path/to/callback.rb" lambda {@resource.send(attr_name, callback_file)}.should_not raise_error @resource.send(attr_name).should == callback_file lambda {@resource.send(attr_name, :this_is_fail)}.should raise_error(ArgumentError) end end end before do @resource = Chef::Resource::Deploy.new("/my/deploy/dir") end resource_has_a_string_attribute(:repo) resource_has_a_string_attribute(:deploy_to) resource_has_a_string_attribute(:role) resource_has_a_string_attribute(:restart_command) resource_has_a_string_attribute(:migration_command) resource_has_a_string_attribute(:user) resource_has_a_string_attribute(:group) resource_has_a_string_attribute(:repository_cache) resource_has_a_string_attribute(:copy_exclude) resource_has_a_string_attribute(:revision) resource_has_a_string_attribute(:remote) resource_has_a_string_attribute(:git_ssh_wrapper) resource_has_a_string_attribute(:svn_username) resource_has_a_string_attribute(:svn_password) resource_has_a_string_attribute(:svn_arguments) resource_has_a_string_attribute(:svn_info_args) resource_has_a_boolean_attribute(:migrate, :defaults_to=>false) resource_has_a_boolean_attribute(:enable_submodules, :defaults_to=>false) resource_has_a_boolean_attribute(:shallow_clone, :defaults_to=>false) it "uses the first argument as the deploy directory" do @resource.deploy_to.should eql("/my/deploy/dir") end # For git, any revision, branch, tag, whatever is resolved to a SHA1 ref. # For svn, the branch is included in the repo URL. # Therefore, revision and branch ARE NOT SEPARATE THINGS it "aliases #revision as #branch" do @resource.branch "stable" @resource.revision.should eql("stable") end it "takes the SCM resource to use as a constant, and defaults to git" do @resource.scm_provider.should eql(Chef::Provider::Git) @resource.scm_provider Chef::Provider::Subversion @resource.scm_provider.should eql(Chef::Provider::Subversion) end it "allows scm providers to be set via symbol" do @resource.scm_provider.should == Chef::Provider::Git @resource.scm_provider :subversion @resource.scm_provider.should == Chef::Provider::Subversion end it "allows scm providers to be set via string" do @resource.scm_provider.should == Chef::Provider::Git @resource.scm_provider "subversion" @resource.scm_provider.should == Chef::Provider::Subversion end it "has a boolean attribute for svn_force_export defaulting to false" do @resource.svn_force_export.should be_false @resource.svn_force_export true @resource.svn_force_export.should be_true lambda {@resource.svn_force_export(10053)}.should raise_error(ArgumentError) end it "takes arbitrary environment variables in a hash" do @resource.environment "RAILS_ENV" => "production" @resource.environment.should == {"RAILS_ENV" => "production"} end it "takes string arguments to environment for backwards compat, setting RAILS_ENV, RACK_ENV, and MERB_ENV" do @resource.environment "production" @resource.environment.should == {"RAILS_ENV"=>"production", "RACK_ENV"=>"production","MERB_ENV"=>"production"} end it "sets destination to $deploy_to/shared/$repository_cache" do @resource.destination.should eql("/my/deploy/dir/shared/cached-copy") end it "sets shared_path to $deploy_to/shared" do @resource.shared_path.should eql("/my/deploy/dir/shared") end it "sets current_path to $deploy_to/current" do @resource.current_path.should eql("/my/deploy/dir/current") end it "gets the current_path correct even if the shared_path is set (regression test)" do @resource.shared_path @resource.current_path.should eql("/my/deploy/dir/current") end it "gives #depth as 5 if shallow clone is true, nil otherwise" do @resource.depth.should be_nil @resource.shallow_clone true @resource.depth.should eql("5") end it "aliases repo as repository" do @resource.repository "git@github.com/opcode/cookbooks.git" @resource.repo.should eql("git@github.com/opcode/cookbooks.git") end it "aliases git_ssh_wrapper as ssh_wrapper" do @resource.ssh_wrapper "git_my_repo.sh" @resource.git_ssh_wrapper.should eql("git_my_repo.sh") end it "has an Array attribute purge_before_symlink, default: log, tmp/pids, public/system" do @resource.purge_before_symlink.should == %w{ log tmp/pids public/system } @resource.purge_before_symlink %w{foo bar baz} @resource.purge_before_symlink.should == %w{foo bar baz} end it "has an Array attribute create_dirs_before_symlink, default: tmp, public, config" do @resource.create_dirs_before_symlink.should == %w{tmp public config} @resource.create_dirs_before_symlink %w{foo bar baz} @resource.create_dirs_before_symlink.should == %w{foo bar baz} end it 'has a Hash attribute symlinks, default: {"system" => "public/system", "pids" => "tmp/pids", "log" => "log"}' do default = { "system" => "public/system", "pids" => "tmp/pids", "log" => "log"} @resource.symlinks.should == default @resource.symlinks "foo" => "bar/baz" @resource.symlinks.should == {"foo" => "bar/baz"} end it 'has a Hash attribute symlink_before_migrate, default "config/database.yml" => "config/database.yml"' do @resource.symlink_before_migrate.should == {"config/database.yml" => "config/database.yml"} @resource.symlink_before_migrate "wtf?" => "wtf is going on" @resource.symlink_before_migrate.should == {"wtf?" => "wtf is going on"} end resource_has_a_callback_attribute :before_migrate resource_has_a_callback_attribute :before_symlink resource_has_a_callback_attribute :before_restart resource_has_a_callback_attribute :after_restart it "aliases restart_command as restart" do @resource.restart "foobaz" @resource.restart_command.should == "foobaz" end it "takes a block for the restart parameter" do restart_like_this = lambda {p :noop} @resource.restart(&restart_like_this) @resource.restart.should == restart_like_this end it "defaults to using the Deploy::Timestamped provider" do @resource.provider.should == Chef::Provider::Deploy::Timestamped end it "allows providers to be set with a full class name" do @resource.provider Chef::Provider::Deploy::Timestamped @resource.provider.should == Chef::Provider::Deploy::Timestamped end it "allows deploy providers to be set via symbol" do @resource.provider :revision @resource.provider.should == Chef::Provider::Deploy::Revision end it "allows deploy providers to be set via string" do @resource.provider "revision" @resource.provider.should == Chef::Provider::Deploy::Revision end it "defaults keep_releases to 5" do @resource.keep_releases.should == 5 end it "allows keep_releases to be set via integer" do @resource.keep_releases 10 @resource.keep_releases.should == 10 end it "enforces a minimum keep_releases of 1" do @resource.keep_releases 0 @resource.keep_releases.should == 1 end describe "when it has a timeout attribute" do let(:ten_seconds) { 10 } before { @resource.timeout(ten_seconds) } it "stores this timeout" do @resource.timeout.should == ten_seconds end end describe "when it has no timeout attribute" do it "should have no default timeout" do @resource.timeout.should be_nil end end describe "when it has meta application root, revision, user, group, scm provider, repository cache, environment, simlinks and migrate" do before do @resource.repository("http://uri.org") @resource.deploy_to("/") @resource.revision("1.2.3") @resource.user("root") @resource.group("pokemon") @resource.scm_provider(Chef::Provider::Git) @resource.repository_cache("cached-copy") @resource.environment({"SUDO" => "TRUE"}) @resource.symlinks({"system" => "public/system"}) @resource.migrate(false) end it "describes its state" do state = @resource.state state[:deploy_to].should == "/" state[:revision].should == "1.2.3" end it "returns the repository URI as its identity" do @resource.identity.should == "http://uri.org" end end end chef-11.8.2/spec/unit/resource/registry_key_spec.rb0000644000004100000410000001314712254362222022365 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2012 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::RegistryKey, "initialize" do before(:each) do @resource = Chef::Resource::RegistryKey.new('HKCU\Software\Raxicoricofallapatorius') end it "should create a new Chef::Resource::RegistryKey" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::RegistryKey) end it "should set the resource_name to :registry_key" do @resource.resource_name.should eql(:registry_key) end it "should set the key equal to the argument to initialize" do @resource.key.should eql('HKCU\Software\Raxicoricofallapatorius') end it "should default recursive to false" do @resource.recursive.should eql(false) end it "should default architecture to :machine" do @resource.architecture.should eql(:machine) end it "should set action to :create" do @resource.action.should eql(:create) end %w{create create_if_missing delete delete_key}.each do |action| it "should allow action #{action}" do @resource.allowed_actions.detect { |a| a == action.to_sym }.should eql(action.to_sym) end end end describe Chef::Resource::RegistryKey, "key" do before(:each) do @resource = Chef::Resource::RegistryKey.new('HKCU\Software\Raxicoricofallapatorius') end it "should allow a string" do @resource.key 'HKCU\Software\Poosh' @resource.key.should eql('HKCU\Software\Poosh') end it "should not allow an integer" do lambda { @resource.send(:key, 100) }.should raise_error(ArgumentError) end it "should not allow a hash" do lambda { @resource.send(:key, { :sonic => "screwdriver" }) }.should raise_error(ArgumentError) end end describe Chef::Resource::RegistryKey, "values" do before(:each) do @resource = Chef::Resource::RegistryKey.new('HKCU\Software\Raxicoricofallapatorius') end it "should allow a single proper hash of registry values" do @resource.values( { :name => 'poosh', :type => :string, :data => 'carmen' } ) @resource.values.should eql([ { :name => 'poosh', :type => :string, :data => 'carmen' } ]) end it "should allow an array of proper hashes of registry values" do @resource.values [ { :name => 'poosh', :type => :string, :data => 'carmen' } ] @resource.values.should eql([ { :name => 'poosh', :type => :string, :data => 'carmen' } ]) end it "should throw an exception if the name field is missing" do lambda { @resource.values [ { :type => :string, :data => 'carmen' } ] }.should raise_error(ArgumentError) end it "should throw an exception if the type field is missing" do lambda { @resource.values [ { :name => 'poosh', :data => 'carmen' } ] }.should raise_error(ArgumentError) end it "should throw an exception if the data field is missing" do lambda { @resource.values [ { :name => 'poosh', :type => :string } ] }.should raise_error(ArgumentError) end it "should throw an exception if extra fields are present" do lambda { @resource.values [ { :name => 'poosh', :type => :string, :data => 'carmen', :screwdriver => 'sonic' } ] }.should raise_error(ArgumentError) end it "should not allow a string" do lambda { @resource.send(:values, 'souffle') }.should raise_error(ArgumentError) end it "should not allow an integer" do lambda { @resource.send(:values, 100) }.should raise_error(ArgumentError) end end describe Chef::Resource::RegistryKey, "recursive" do before(:each) do @resource = Chef::Resource::RegistryKey.new('HKCU\Software\Raxicoricofallapatorius') end it "should allow a boolean" do @resource.recursive(true) @resource.recursive.should eql(true) end it "should not allow a hash" do lambda { @resource.recursive({:sonic => :screwdriver}) }.should raise_error(ArgumentError) end it "should not allow an array" do lambda { @resource.recursive([:nose, :chin]) }.should raise_error(ArgumentError) end it "should not allow a string" do lambda { @resource.recursive('souffle') }.should raise_error(ArgumentError) end it "should not allow an integer" do lambda { @resource.recursive(100) }.should raise_error(ArgumentError) end end describe Chef::Resource::RegistryKey, "architecture" do before(:each) do @resource = Chef::Resource::RegistryKey.new('HKCU\Software\Raxicoricofallapatorius') end [ :i386, :x86_64, :machine ].each do |arch| it "should allow #{arch} as a symbol" do @resource.architecture(arch) @resource.architecture.should eql(arch) end end it "should not allow a hash" do lambda { @resource.architecture({:sonic => :screwdriver}) }.should raise_error(ArgumentError) end it "should not allow an array" do lambda { @resource.architecture([:nose, :chin]) }.should raise_error(ArgumentError) end it "should not allow a string" do lambda { @resource.architecture('souffle') }.should raise_error(ArgumentError) end it "should not allow an integer" do lambda { @resource.architecture(100) }.should raise_error(ArgumentError) end end chef-11.8.2/spec/unit/resource/template_spec.rb0000644000004100000410000001467112254362222021463 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Template do before(:each) do @resource = Chef::Resource::Template.new("fakey_fakerton") end describe "initialize" do it "should create a new Chef::Resource::Template" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::File) @resource.should be_a_kind_of(Chef::Resource::Template) end end describe "source" do it "should accept a string for the template source" do @resource.source "something" @resource.source.should eql("something") end it "should have a default based on the param name with .erb appended" do @resource.source.should eql("fakey_fakerton.erb") end it "should use only the basename of the file as the default" do r = Chef::Resource::Template.new("/tmp/obit/fakey_fakerton") r.source.should eql("fakey_fakerton.erb") end end describe "variables" do it "should accept a hash for the variable list" do @resource.variables({ :reluctance => :awkward }) @resource.variables.should == { :reluctance => :awkward } end end describe "cookbook" do it "should accept a string for the cookbook name" do @resource.cookbook("foo") @resource.cookbook.should == "foo" end it "should default to nil" do @resource.cookbook.should == nil end end describe "local" do it "should accept a boolean for whether a template is local or remote" do @resource.local(true) @resource.local.should == true end it "should default to false" do @resource.local.should == false end end describe "when it has a path, owner, group, mode, and checksum" do before do @resource.path("/tmp/foo.txt") @resource.owner("root") @resource.group("wheel") @resource.mode("0644") @resource.checksum("1" * 64) end context "on unix", :unix_only do it "describes its state" do state = @resource.state state[:owner].should == "root" state[:group].should == "wheel" state[:mode].should == "0644" state[:checksum].should == "1" * 64 end end context "on windows", :windows_only do # according to Chef::Resource::File, windows state attributes are rights + deny_rights pending "it describes its state" end it "returns the file path as its identity" do @resource.identity.should == "/tmp/foo.txt" end end describe "defining helper methods" do module ExampleHelpers def static_example "static_example" end end it "collects helper method bodies as blocks" do @resource.helper(:example_1) { "example_1" } @resource.helper(:example_2) { "example_2" } @resource.inline_helper_blocks[:example_1].call.should == "example_1" @resource.inline_helper_blocks[:example_2].call.should == "example_2" end it "compiles helper methods into a module" do @resource.helper(:example_1) { "example_1" } @resource.helper(:example_2) { "example_2" } modules = @resource.helper_modules modules.should have(1).module o = Object.new modules.each {|m| o.extend(m)} o.example_1.should == "example_1" o.example_2.should == "example_2" end it "compiles helper methods with arguments into a module" do @resource.helper(:shout) { |quiet| quiet.upcase } modules = @resource.helper_modules o = Object.new modules.each {|m| o.extend(m)} o.shout("shout").should == "SHOUT" end it "raises an error when attempting to define a helper method without a method body" do lambda { @resource.helper(:example) }.should raise_error(Chef::Exceptions::ValidationFailed) end it "raises an error when attempting to define a helper method with a non-Symbod method name" do lambda { @resource.helper("example") { "fail" } }.should raise_error(Chef::Exceptions::ValidationFailed) end it "collects helper module bodies as blocks" do @resource.helpers do def example_1 "example_1" end end module_body = @resource.inline_helper_modules.first module_body.should be_a(Proc) end it "compiles helper module bodies into modules" do @resource.helpers do def example_1 "example_1" end end modules = @resource.helper_modules modules.should have(1).module o = Object.new modules.each {|m| o.extend(m)} o.example_1.should == "example_1" end it "raises an error when no block or module name is given for helpers definition" do lambda { @resource.helpers() }.should raise_error(Chef::Exceptions::ValidationFailed) end it "raises an error when a non-module is given for helpers definition" do lambda { @resource.helpers("NotAModule") }.should raise_error(Chef::Exceptions::ValidationFailed) end it "raises an error when a module name and block are both given for helpers definition" do lambda { @resource.helpers(ExampleHelpers) { module_code } }.should raise_error(Chef::Exceptions::ValidationFailed) end it "collects helper modules" do @resource.helpers(ExampleHelpers) @resource.helper_modules.should include(ExampleHelpers) end it "combines all helpers into a set of compiled modules" do @resource.helpers(ExampleHelpers) @resource.helpers do def inline_module "inline_module" end end @resource.helper(:inline_method) { "inline_method" } @resource.should have(3).helper_modules o = Object.new @resource.helper_modules.each {|m| o.extend(m)} o.static_example.should == "static_example" o.inline_module.should == "inline_module" o.inline_method.should == "inline_method" end end end chef-11.8.2/spec/unit/resource/http_request_spec.rb0000644000004100000410000000335612254362222022375 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::HttpRequest do before(:each) do @resource = Chef::Resource::HttpRequest.new("fakey_fakerton") end it "should create a new Chef::Resource::HttpRequest" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::HttpRequest) end it "should set url to a string" do @resource.url "http://slashdot.org" @resource.url.should eql("http://slashdot.org") end it "should set the message to the name by default" do @resource.message.should eql("fakey_fakerton") end it "should set message to a string" do @resource.message "monkeybars" @resource.message.should eql("monkeybars") end describe "when it has a message and headers" do before do @resource.url("http://www.trololol.net") @resource.message("Get sum post brah.") @resource.headers({"head" => "tail"}) end it "returns the url as its identity" do @resource.identity.should == "http://www.trololol.net" end end end chef-11.8.2/spec/unit/resource/csh_spec.rb0000644000004100000410000000223412254362222020415 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Csh do before(:each) do @resource = Chef::Resource::Csh.new("fakey_fakerton") end it "should create a new Chef::Resource::Csh" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::Csh) end it "should have a resource name of :csh" do @resource.resource_name.should eql(:csh) end it "should have an interpreter of csh" do @resource.interpreter.should eql("csh") end end chef-11.8.2/spec/unit/resource/ohai_spec.rb0000644000004100000410000000321412254362222020557 0ustar www-datawww-data# # Author:: Michael Leinartas () # Copyright:: Copyright (c) 2010 Michael Leinartas # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Ohai do before(:each) do @resource = Chef::Resource::Ohai.new("ohai_reload") end it "should create a new Chef::Resource::Ohai" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::Ohai) end it "should have a resource name of :ohai" do @resource.resource_name.should eql(:ohai) end it "should have a default action of create" do @resource.action.should eql(:reload) end it "should allow you to set the plugin attribute" do @resource.plugin "passwd" @resource.plugin.should eql("passwd") end describe "when it has a plugin value" do before do @resource.name("test") @resource.plugin("passwd") end it "describes its state" do state = @resource.state state[:plugin].should == "passwd" end it "returns the name as its identity" do @resource.identity.should == "test" end end end chef-11.8.2/spec/unit/resource/perl_spec.rb0000644000004100000410000000224412254362222020603 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Perl do before(:each) do @resource = Chef::Resource::Perl.new("fakey_fakerton") end it "should create a new Chef::Resource::Perl" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::Perl) end it "should have a resource name of :perl" do @resource.resource_name.should eql(:perl) end it "should have an interpreter of perl" do @resource.interpreter.should eql("perl") end end chef-11.8.2/spec/unit/resource/powershell_spec.rb0000644000004100000410000000270412254362222022026 0ustar www-datawww-data# # Author:: Adam Edwards () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::PowershellScript do before(:each) do node = Chef::Node.new node.default["kernel"] = Hash.new node.default["kernel"][:machine] = :x86_64.to_s run_context = Chef::RunContext.new(node, nil, nil) @resource = Chef::Resource::PowershellScript.new("powershell_unit_test", run_context) end it "should create a new Chef::Resource::PowershellScript" do @resource.should be_a_kind_of(Chef::Resource::PowershellScript) end context "windowsscript" do let(:resource_instance) { @resource } let(:resource_instance_name ) { @resource.command } let(:resource_name) { :powershell_script } let(:interpreter_file_name) { 'powershell.exe' } it_should_behave_like "a Windows script resource" end end chef-11.8.2/spec/unit/resource/conditional_spec.rb0000644000004100000410000001064612254362222022151 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'ostruct' describe Chef::Resource::Conditional do before do Mixlib::ShellOut.any_instance.stub(:run_command).and_return(nil) @status = OpenStruct.new(:success? => true) Mixlib::ShellOut.any_instance.stub(:status).and_return(@status) end describe "when created as an `only_if`" do describe "after running a successful command" do before do @conditional = Chef::Resource::Conditional.only_if("true") end it "indicates that resource convergence should continue" do @conditional.continue?.should be_true end end describe "after running a negative/false command" do before do @status.send("success?=", false) @conditional = Chef::Resource::Conditional.only_if("false") end it "indicates that resource convergence should not continue" do @conditional.continue?.should be_false end end describe 'after running a command which timed out' do before do @conditional = Chef::Resource::Conditional.only_if("false") @conditional.stub(:shell_out).and_raise(Chef::Exceptions::CommandTimeout) end it 'indicates that resource convergence should not continue' do @conditional.continue?.should be_false end it 'should log a warning' do Chef::Log.should_receive(:warn).with("Command 'false' timed out") @conditional.continue? end end describe "after running a block that returns a truthy value" do before do @conditional = Chef::Resource::Conditional.only_if { Object.new } end it "indicates that resource convergence should continue" do @conditional.continue?.should be_true end end describe "after running a block that returns a falsey value" do before do @conditional = Chef::Resource::Conditional.only_if { nil } end it "indicates that resource convergence should not continue" do @conditional.continue?.should be_false end end end describe "when created as a `not_if`" do describe "after running a successful/true command" do before do @conditional = Chef::Resource::Conditional.not_if("true") end it "indicates that resource convergence should not continue" do @conditional.continue?.should be_false end end describe "after running a failed/false command" do before do @status.send("success?=", false) @conditional = Chef::Resource::Conditional.not_if("false") end it "indicates that resource convergence should continue" do @conditional.continue?.should be_true end end describe 'after running a command which timed out' do before do @conditional = Chef::Resource::Conditional.not_if("false") @conditional.stub(:shell_out).and_raise(Chef::Exceptions::CommandTimeout) end it 'indicates that resource convergence should continue' do @conditional.continue?.should be_true end it 'should log a warning' do Chef::Log.should_receive(:warn).with("Command 'false' timed out") @conditional.continue? end end describe "after running a block that returns a truthy value" do before do @conditional = Chef::Resource::Conditional.not_if { Object.new } end it "indicates that resource convergence should not continue" do @conditional.continue?.should be_false end end describe "after running a block that returns a falsey value" do before do @conditional = Chef::Resource::Conditional.not_if { nil } end it "indicates that resource convergence should continue" do @conditional.continue?.should be_true end end end end chef-11.8.2/spec/unit/resource/yum_package_spec.rb0000644000004100000410000000524012254362222022125 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::YumPackage, "initialize" do before(:each) do @resource = Chef::Resource::YumPackage.new("foo") end it "should return a Chef::Resource::YumPackage" do @resource.should be_a_kind_of(Chef::Resource::YumPackage) end it "should set the resource_name to :yum_package" do @resource.resource_name.should eql(:yum_package) end it "should set the provider to Chef::Provider::Package::Yum" do @resource.provider.should eql(Chef::Provider::Package::Yum) end end describe Chef::Resource::YumPackage, "arch" do before(:each) do @resource = Chef::Resource::YumPackage.new("foo") end it "should set the arch variable to whatever is passed in" do @resource.arch("i386") @resource.arch.should eql("i386") end end describe Chef::Resource::YumPackage, "flush_cache" do before(:each) do @resource = Chef::Resource::YumPackage.new("foo") end it "should default the flush timing to false" do flush_hash = { :before => false, :after => false } @resource.flush_cache.should == flush_hash end it "should allow you to set the flush timing with an array" do flush_array = [ :before, :after ] flush_hash = { :before => true, :after => true } @resource.flush_cache(flush_array) @resource.flush_cache.should == flush_hash end it "should allow you to set the flush timing with a hash" do flush_hash = { :before => true, :after => true } @resource.flush_cache(flush_hash) @resource.flush_cache.should == flush_hash end end describe Chef::Resource::YumPackage, "allow_downgrade" do before(:each) do @resource = Chef::Resource::YumPackage.new("foo") end it "should allow you to specify whether allow_downgrade is true or false" do lambda { @resource.allow_downgrade true }.should_not raise_error(ArgumentError) lambda { @resource.allow_downgrade false }.should_not raise_error(ArgumentError) lambda { @resource.allow_downgrade "monkey" }.should raise_error(ArgumentError) end end chef-11.8.2/spec/unit/resource/ruby_block_spec.rb0000644000004100000410000000335212254362222021775 0ustar www-datawww-data# # Author:: AJ Christensen () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::RubyBlock do before(:each) do @resource = Chef::Resource::RubyBlock.new("fakey_fakerton") end it "should create a new Chef::Resource::RubyBlock" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::RubyBlock) end it "should have a default action of 'create'" do @resource.action.should eql("run") end it "should have a resource name of :ruby_block" do @resource.resource_name.should eql(:ruby_block) end it "should accept a ruby block/proc/.. for the 'block' parameter" do @resource.block do "foo" end.call.should eql("foo") end it "allows the action to be 'create'" do @resource.action :create @resource.action.should == [:create] end describe "when it has been initialized with block code" do before do @resource.block_name("puts 'harrrr'") end it "returns the block as its identity" do @resource.identity.should == "puts 'harrrr'" end end end chef-11.8.2/spec/unit/config_spec.rb0000644000004100000410000002764512254362222017273 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Kyle Goodwin () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/exceptions' describe Chef::Config do before(:all) do @original_env = { 'HOME' => ENV['HOME'], 'SYSTEMDRIVE' => ENV['SYSTEMDRIVE'], 'HOMEPATH' => ENV['HOMEPATH'], 'USERPROFILE' => ENV['USERPROFILE'] } end describe "config attribute writer: chef_server_url" do before do Chef::Config.chef_server_url = "https://junglist.gen.nz" end it "sets the server url" do Chef::Config.chef_server_url.should == "https://junglist.gen.nz" end context "when the url has a leading space" do before do Chef::Config.chef_server_url = " https://junglist.gen.nz" end it "strips the space from the url when setting" do Chef::Config.chef_server_url.should == "https://junglist.gen.nz" end end context "when the url is a frozen string" do before do Chef::Config.chef_server_url = " https://junglist.gen.nz".freeze end it "strips the space from the url when setting without raising an error" do Chef::Config.chef_server_url.should == "https://junglist.gen.nz" end end end describe "when configuring formatters" do # if TTY and not(force-logger) # formatter = configured formatter or default formatter # formatter goes to STDOUT/ERR # if log file is writeable # log level is configured level or info # log location is file # else # log level is warn # log location is STDERR # end # elsif not(TTY) and force formatter # formatter = configured formatter or default formatter # if log_location specified # formatter goes to log_location # else # formatter goes to STDOUT/ERR # end # else # formatter = "null" # log_location = configured-value or defualt # log_level = info or defualt # end # it "has an empty list of formatters by default" do Chef::Config.formatters.should == [] end it "configures a formatter with a short name" do Chef::Config.add_formatter(:doc) Chef::Config.formatters.should == [[:doc, nil]] end it "configures a formatter with a file output" do Chef::Config.add_formatter(:doc, "/var/log/formatter.log") Chef::Config.formatters.should == [[:doc, "/var/log/formatter.log"]] end end describe "class method: manage_secret_key" do before do Chef::FileCache.stub!(:load).and_return(true) Chef::FileCache.stub!(:has_key?).with("chef_server_cookie_id").and_return(false) end it "should generate and store a chef server cookie id" do Chef::FileCache.should_receive(:store).with("chef_server_cookie_id", /\w{40}/).and_return(true) Chef::Config.manage_secret_key end describe "when the filecache has a chef server cookie id key" do before do Chef::FileCache.stub!(:has_key?).with("chef_server_cookie_id").and_return(true) end it "should not generate and store a chef server cookie id" do Chef::FileCache.should_not_receive(:store).with("chef_server_cookie_id", /\w{40}/) Chef::Config.manage_secret_key end end end describe "config attribute writer: log_method=" do describe "when given an object that responds to sync= e.g. IO" do it "should configure itself to use the IO as log_location" do Chef::Config.log_location = STDOUT Chef::Config.log_location.should == STDOUT end end describe "when given an object that is stringable (to_str)" do before do @mockfile = mock("File", :path => "/var/log/chef/client.log", :sync= => true) File.should_receive(:new). with("/var/log/chef/client.log", "a"). and_return(@mockfile) end it "should configure itself to use a File object based upon the String" do Chef::Config.log_location = "/var/log/chef/client.log" Chef::Config.log_location.path.should == "/var/log/chef/client.log" end end end describe "class method: plaform_specific_path" do it "should return given path on non-windows systems" do platform_mock :unix do path = "/etc/chef/cookbooks" Chef::Config.platform_specific_path(path).should == "/etc/chef/cookbooks" end end it "should return a windows path on windows systems" do platform_mock :windows do path = "/etc/chef/cookbooks" ENV.stub!(:[]).with('SYSTEMDRIVE').and_return('C:') # match on a regex that looks for the base path with an optional # system drive at the beginning (c:) # system drive is not hardcoded b/c it can change and b/c it is not present on linux systems Chef::Config.platform_specific_path(path).should == "C:\\chef\\cookbooks" end end end describe "default values" do it "Chef::Config[:file_backup_path] defaults to /var/chef/backup" do backup_path = if windows? "#{ENV['SYSTEMDRIVE']}\\chef\\backup" else "/var/chef/backup" end Chef::Config[:file_backup_path].should == backup_path end it "Chef::Config[:ssl_verify_mode] defaults to :verify_none" do Chef::Config[:ssl_verify_mode].should == :verify_none end it "Chef::Config[:ssl_ca_path] defaults to nil" do Chef::Config[:ssl_ca_path].should be_nil end describe "when on UNIX" do before do Chef::Config.stub(:on_windows?).and_return(false) end it "Chef::Config[:ssl_ca_file] defaults to nil" do Chef::Config[:ssl_ca_file].should be_nil end end it "Chef::Config[:data_bag_path] defaults to /var/chef/data_bags" do data_bag_path = Chef::Config.platform_specific_path("/var/chef/data_bags") Chef::Config[:data_bag_path].should == data_bag_path end it "Chef::Config[:environment_path] defaults to /var/chef/environments" do environment_path = if windows? "C:\\chef\\environments" else "/var/chef/environments" end Chef::Config[:environment_path].should == environment_path end describe "joining platform specific paths" do context "on UNIX" do before do Chef::Config.stub(:on_windows?).and_return(false) end it "joins components when some end with separators" do Chef::Config.path_join("/foo/", "bar", "baz").should == "/foo/bar/baz" end it "joins components that don't end in separators" do Chef::Config.path_join("/foo", "bar", "baz").should == "/foo/bar/baz" end end context "on Windows" do before do Chef::Config.stub(:on_windows?).and_return(true) end it "joins components with the windows separator" do Chef::Config.path_join('c:\\foo\\', 'bar', "baz").should == 'c:\\foo\\bar\\baz' end end end describe "setting the config dir" do before do Chef::Config.stub(:on_windows?).and_return(false) Chef::Config.config_file = "/etc/chef/client.rb" end context "by default" do it "is the parent dir of the config file" do Chef::Config.config_dir.should == "/etc/chef" end end context "when chef is running in local mode" do before do Chef::Config.local_mode = true Chef::Config.user_home = "/home/charlie" end it "is in the user's home dir" do Chef::Config.config_dir.should == "/home/charlie/.chef/" end end context "when explicitly set" do before do Chef::Config.config_dir = "/other/config/dir/" end it "uses the explicit value" do Chef::Config.config_dir.should == "/other/config/dir/" end end end describe "finding the windows embedded dir" do let(:default_config_location) { "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.6.0/lib/chef/config.rb" } let(:alternate_install_location) { "c:/my/alternate/install/place/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.6.0/lib/chef/config.rb" } let(:non_omnibus_location) { "c:/my/dev/stuff/lib/ruby/gems/1.9.1/gems/chef-11.6.0/lib/chef/config.rb" } let(:default_ca_file) { "c:/opscode/chef/embedded/ssl/certs/cacert.pem" } it "finds the embedded dir in the default location" do Chef::Config.stub(:_this_file).and_return(default_config_location) Chef::Config.embedded_dir.should == "c:/opscode/chef/embedded" end it "finds the embedded dir in a custom install location" do Chef::Config.stub(:_this_file).and_return(alternate_install_location) Chef::Config.embedded_dir.should == "c:/my/alternate/install/place/chef/embedded" end it "doesn't error when not in an omnibus install" do Chef::Config.stub(:_this_file).and_return(non_omnibus_location) Chef::Config.embedded_dir.should be_nil end it "sets the ssl_ca_cert path if the cert file is available" do Chef::Config.stub(:_this_file).and_return(default_config_location) Chef::Config.stub(:on_windows?).and_return(true) File.stub(:exist?).with(default_ca_file).and_return(true) Chef::Config.ssl_ca_file.should == default_ca_file end end end describe "Chef::Config[:user_home]" do it "should set when HOME is provided" do ENV['HOME'] = "/home/kitten" load File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "lib", "chef", "config.rb")) Chef::Config[:user_home].should == "/home/kitten" end it "should be set when only USERPROFILE is provided" do ENV['HOME'], ENV['SYSTEMDRIVE'], ENV['HOMEPATH'] = nil, nil, nil ENV['USERPROFILE'] = "/users/kitten" load File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "lib", "chef", "config.rb")) Chef::Config[:user_home].should == "/users/kitten" end after(:each) do @original_env.each do |env_setting| ENV[env_setting[0]] = env_setting[1] end end end describe "Chef::Config[:encrypted_data_bag_secret]" do db_secret_default_path = Chef::Config.platform_specific_path("/etc/chef/encrypted_data_bag_secret") let(:db_secret_default_path){ db_secret_default_path } before do File.stub(:exist?).with(db_secret_default_path).and_return(secret_exists) # ugh...the only way to properly test this since the conditional # is evaluated at file load/require time. $LOADED_FEATURES.delete_if{|f| f =~ /chef\/config\.rb/} require 'chef/config' end context "#{db_secret_default_path} exists" do let(:secret_exists) { true } it "sets the value to #{db_secret_default_path}" do Chef::Config[:encrypted_data_bag_secret].should eq db_secret_default_path end end context "#{db_secret_default_path} does not exist" do let(:secret_exists) { false } it "sets the value to nil" do Chef::Config[:encrypted_data_bag_secret].should be_nil end end end describe "Chef::Config[:log_location]" do it "raises ConfigurationError when log_location directory is missing" do missing_path = "/tmp/non-existing-dir/file" expect{Chef::Config.log_location = missing_path}.to raise_error Chef::Exceptions::ConfigurationError end end end chef-11.8.2/spec/unit/cookbook_version_spec.rb0000644000004100000410000002712512254362222021372 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'spec_helper' describe Chef::CookbookVersion do describe "when first created" do before do @cookbook_version = Chef::CookbookVersion.new("tatft") end it "has a name" do @cookbook_version.name.should == 'tatft' end it "has no attribute files" do @cookbook_version.attribute_filenames.should be_empty end it "has no resource definition files" do @cookbook_version.definition_filenames.should be_empty end it "has no cookbook files" do @cookbook_version.file_filenames.should be_empty end it "has no recipe files" do @cookbook_version.recipe_filenames.should be_empty end it "has no library files" do @cookbook_version.library_filenames.should be_empty end it "has no LWRP resource files" do @cookbook_version.resource_filenames.should be_empty end it "has no LWRP provider files" do @cookbook_version.provider_filenames.should be_empty end it "has no metadata files" do @cookbook_version.metadata_filenames.should be_empty end it "is not frozen" do @cookbook_version.should_not be_frozen_version end it "can be frozen" do @cookbook_version.freeze_version @cookbook_version.should be_frozen_version end it "is \"ready\"" do # WTF is this? what are the valid states? and why aren't they set with encapsulating methods? # [Dan 15-Jul-2010] @cookbook_version.status.should == :ready end it "has empty metadata" do @cookbook_version.metadata.should == Chef::Cookbook::Metadata.new end it "creates a manifest hash of its contents" do expected = {"recipes"=>[], "definitions"=>[], "libraries"=>[], "attributes"=>[], "files"=>[], "templates"=>[], "resources"=>[], "providers"=>[], "root_files"=>[], "cookbook_name"=>"tatft", "metadata"=>Chef::Cookbook::Metadata.new, "version"=>"0.0.0", "name"=>"tatft-0.0.0"} @cookbook_version.manifest.should == expected end end describe "after the cookbook has been loaded" do MD5 = /[0-9a-f]{32}/ before do # Currently the cookbook loader finds all the files then tells CookbookVersion # where they are. @cookbook_version = Chef::CookbookVersion.new("tatft") @cookbook = Hash.new { |hash, key| hash[key] = [] } cookbook_root = File.join(CHEF_SPEC_DATA, 'cb_version_cookbooks', 'tatft') # Dunno if the paths here are representitive of what is set by CookbookLoader... @cookbook[:attribute_filenames] = Dir[File.join(cookbook_root, 'attributes', '**', '*.rb')] @cookbook[:definition_filenames] = Dir[File.join(cookbook_root, 'definitions', '**', '*.rb')] @cookbook[:file_filenames] = Dir[File.join(cookbook_root, 'files', '**', '*.tgz')] @cookbook[:recipe_filenames] = Dir[File.join(cookbook_root, 'recipes', '**', '*.rb')] @cookbook[:template_filenames] = Dir[File.join(cookbook_root, 'templates', '**', '*.erb')] @cookbook[:library_filenames] = Dir[File.join(cookbook_root, 'libraries', '**', '*.rb')] @cookbook[:resource_filenames] = Dir[File.join(cookbook_root, 'resources', '**', '*.rb')] @cookbook[:provider_filenames] = Dir[File.join(cookbook_root, 'providers', '**', '*.rb')] @cookbook[:root_filenames] = Array(File.join(cookbook_root, 'README.rdoc')) @cookbook[:metadata_filenames] = Array(File.join(cookbook_root, 'metadata.json')) @cookbook_version.attribute_filenames = @cookbook[:attribute_filenames] @cookbook_version.definition_filenames = @cookbook[:definition_filenames] @cookbook_version.recipe_filenames = @cookbook[:recipe_filenames] @cookbook_version.template_filenames = @cookbook[:template_filenames] @cookbook_version.file_filenames = @cookbook[:file_filenames] @cookbook_version.library_filenames = @cookbook[:library_filenames] @cookbook_version.resource_filenames = @cookbook[:resource_filenames] @cookbook_version.provider_filenames = @cookbook[:provider_filenames] @cookbook_version.root_filenames = @cookbook[:root_filenames] @cookbook_version.metadata_filenames = @cookbook[:metadata_filenames] # Used to test file-specificity related file lookups @node = Chef::Node.new @node.set[:platform] = "ubuntu" @node.set[:platform_version] = "13.04" @node.name("testing") end it "generates a manifest containing the cookbook's files" do manifest = @cookbook_version.manifest manifest["metadata"].should == Chef::Cookbook::Metadata.new manifest["cookbook_name"].should == "tatft" manifest["recipes"].should have(1).recipe_file recipe = manifest["recipes"].first recipe["name"].should == "default.rb" recipe["path"].should == "recipes/default.rb" recipe["checksum"].should match(MD5) recipe["specificity"].should == "default" manifest["definitions"].should have(1).definition_file definition = manifest["definitions"].first definition["name"].should == "runit_service.rb" definition["path"].should == "definitions/runit_service.rb" definition["checksum"].should match(MD5) definition["specificity"].should == "default" manifest["libraries"].should have(1).library_file library = manifest["libraries"].first library["name"].should == "ownage.rb" library["path"].should == "libraries/ownage.rb" library["checksum"].should match(MD5) library["specificity"].should == "default" manifest["attributes"].should have(1).attribute_file attribute_file = manifest["attributes"].first attribute_file["name"].should == "default.rb" attribute_file["path"].should == "attributes/default.rb" attribute_file["checksum"].should match(MD5) attribute_file["specificity"].should == "default" manifest["files"].should have(1).cookbook_file cookbook_file = manifest["files"].first cookbook_file["name"].should == "giant_blob.tgz" cookbook_file["path"].should == "files/default/giant_blob.tgz" cookbook_file["checksum"].should match(MD5) cookbook_file["specificity"].should == "default" manifest["templates"].should have(1).template template = manifest["templates"].first template["name"].should == "configuration.erb" template["path"].should == "templates/default/configuration.erb" template["checksum"].should match(MD5) template["specificity"].should == "default" manifest["resources"].should have(1).lwr lwr = manifest["resources"].first lwr["name"].should == "lwr.rb" lwr["path"].should == "resources/lwr.rb" lwr["checksum"].should match(MD5) lwr["specificity"].should == "default" manifest["providers"].should have(1).lwp lwp = manifest["providers"].first lwp["name"].should == "lwp.rb" lwp["path"].should == "providers/lwp.rb" lwp["checksum"].should match(MD5) lwp["specificity"].should == "default" manifest["root_files"].should have(1).file_in_the_cookbook_root readme = manifest["root_files"].first readme["name"].should == "README.rdoc" readme["path"].should == "README.rdoc" readme["checksum"].should match(MD5) readme["specificity"].should == "default" end it "determines whether a template is available for a given node" do @cookbook_version.should have_template_for_node(@node, "configuration.erb") @cookbook_version.should_not have_template_for_node(@node, "missing.erb") end it "determines whether a cookbook_file is available for a given node" do @cookbook_version.should have_cookbook_file_for_node(@node, "giant_blob.tgz") @cookbook_version.should_not have_cookbook_file_for_node(@node, "missing.txt") end describe "raises an error when attempting to load a missing cookbook_file and" do before do node = Chef::Node.new.tap do |n| n.name("sample.node") n.automatic_attrs[:fqdn] = "sample.example.com" n.automatic_attrs[:platform] = "ubuntu" n.automatic_attrs[:platform_version] = "10.04" end @attempt_to_load_file = lambda { @cookbook_version.preferred_manifest_record(node, :files, "no-such-thing.txt") } end it "describes the cookbook and version" do useful_explanation = Regexp.new(Regexp.escape("Cookbook 'tatft' (0.0.0) does not contain")) @attempt_to_load_file.should raise_error(Chef::Exceptions::FileNotFound, useful_explanation) end it "lists suggested places to look" do useful_explanation = Regexp.new(Regexp.escape("files/default/no-such-thing.txt")) @attempt_to_load_file.should raise_error(Chef::Exceptions::FileNotFound, useful_explanation) end end end describe "<=>" do it "should sort based on the version number" do examples = [ # smaller, larger ["1.0", "2.0"], ["1.2.3", "1.2.4"], ["1.2.3", "1.3.0"], ["1.2.3", "1.3"], ["1.2.3", "2.1.1"], ["1.2.3", "2.1"], ["1.2", "1.2.4"], ["1.2", "1.3.0"], ["1.2", "1.3"], ["1.2", "2.1.1"], ["1.2", "2.1"] ] examples.each do |smaller, larger| sm = Chef::CookbookVersion.new("foo") lg = Chef::CookbookVersion.new("foo") sm.version = smaller lg.version = larger sm.should be < lg lg.should be > sm sm.should_not == lg end end it "should equate versions 1.2 and 1.2.0" do a = Chef::CookbookVersion.new("foo") b = Chef::CookbookVersion.new("foo") a.version = "1.2" b.version = "1.2.0" a.should == b end it "should not allow you to sort cookbooks with different names" do apt = Chef::CookbookVersion.new "apt" apt.version = "1.0" god = Chef::CookbookVersion.new "god" god.version = "2.0" lambda {apt <=> god}.should raise_error(Chef::Exceptions::CookbookVersionNameMismatch) end end describe "when you set a version" do before do @cbv = Chef::CookbookVersion.new("version validation") end it "should accept valid cookbook versions" do good_versions = %w(1.2 1.2.3 1000.80.50000 0.300.25) good_versions.each do |v| @cbv.version = v end end it "should raise InvalidVersion for bad cookbook versions" do bad_versions = ["1.2.3.4", "1.2.a4", "1", "a", "1.2 3", "1.2 a", "1 2 3", "1-2-3", "1_2_3", "1.2_3", "1.2-3"] the_error = Chef::Exceptions::InvalidCookbookVersion bad_versions.each do |v| lambda {@cbv.version = v}.should raise_error(the_error) end end end end chef-11.8.2/spec/unit/environment_spec.rb0000644000004100000410000004235212254362222020362 0ustar www-datawww-data# # Author:: Stephen Delano () # Author:: Seth Falcon () # Author:: John Keiser () # Author:: Kyle Goodwin () # Copyright:: Copyright 2010-2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/environment' describe Chef::Environment do before(:each) do @environment = Chef::Environment.new end describe "initialize" do it "should be a Chef::Environment" do @environment.should be_a_kind_of(Chef::Environment) end end describe "name" do it "should let you set the name to a string" do @environment.name("production").should == "production" end it "should return the current name" do @environment.name("production") @environment.name.should == "production" end it "should not accept spaces" do lambda { @environment.name("production environment") }.should raise_error(ArgumentError) end it "should not accept anything but strings" do lambda { @environment.name(Array.new) }.should raise_error(ArgumentError) lambda { @environment.name(Hash.new) }.should raise_error(ArgumentError) lambda { @environment.name(2) }.should raise_error(ArgumentError) end end describe "description" do it "should let you set the description to a string" do @environment.description("this is my test environment").should == "this is my test environment" end it "should return the correct description" do @environment.description("I like running tests") @environment.description.should == "I like running tests" end it "should not accept anything but strings" do lambda { @environment.description(Array.new) }.should raise_error(ArgumentError) lambda { @environment.description(Hash.new) }.should raise_error(ArgumentError) lambda { @environment.description(42) }.should raise_error(ArgumentError) end end describe "default attributes" do it "should let you set the attributes hash explicitly" do @environment.default_attributes({ :one => 'two' }).should == { :one => 'two' } end it "should let you return the attributes hash" do @environment.default_attributes({ :one => 'two' }) @environment.default_attributes.should == { :one => 'two' } end it "should throw an ArgumentError if we aren't a kind of hash" do lambda { @environment.default_attributes(Array.new) }.should raise_error(ArgumentError) end end describe "override attributes" do it "should let you set the attributes hash explicitly" do @environment.override_attributes({ :one => 'two' }).should == { :one => 'two' } end it "should let you return the attributes hash" do @environment.override_attributes({ :one => 'two' }) @environment.override_attributes.should == { :one => 'two' } end it "should throw an ArgumentError if we aren't a kind of hash" do lambda { @environment.override_attributes(Array.new) }.should raise_error(ArgumentError) end end describe "cookbook_versions" do before(:each) do @cookbook_versions = { "apt" => "= 1.0.0", "god" => "= 2.0.0", "apache2" => "= 4.2.0" } end it "should let you set the cookbook versions in a hash" do @environment.cookbook_versions(@cookbook_versions).should == @cookbook_versions end it "should return the cookbook versions" do @environment.cookbook_versions(@cookbook_versions) @environment.cookbook_versions.should == @cookbook_versions end it "should not accept anything but a hash" do lambda { @environment.cookbook_versions("I am a string!") }.should raise_error(ArgumentError) lambda { @environment.cookbook_versions(Array.new) }.should raise_error(ArgumentError) lambda { @environment.cookbook_versions(42) }.should raise_error(ArgumentError) end it "should validate the hash" do Chef::Environment.should_receive(:validate_cookbook_versions).with(@cookbook_versions).and_return true @environment.cookbook_versions(@cookbook_versions) end end describe "cookbook" do it "should set the version of the cookbook in the cookbook_versions hash" do @environment.cookbook("apt", "~> 1.2.3") @environment.cookbook_versions["apt"].should == "~> 1.2.3" end it "should validate the cookbook version it is passed" do Chef::Environment.should_receive(:validate_cookbook_version).with(">= 1.2.3").and_return true @environment.cookbook("apt", ">= 1.2.3") end end describe "update_from!" do before(:each) do @environment.name("prod") @environment.description("this is prod") @environment.cookbook_versions({ "apt" => "= 1.2.3" }) @example = Chef::Environment.new @example.name("notevenprod") @example.description("this is pre-prod") @example.cookbook_versions({ "apt" => "= 2.3.4" }) end it "should update everything but name" do @environment.update_from!(@example) @environment.name.should == "prod" @environment.description.should == @example.description @environment.cookbook_versions.should == @example.cookbook_versions end end describe "to_hash" do before(:each) do @environment.name("spec") @environment.description("Where we run the spec tests") @environment.cookbook_versions({:apt => "= 1.2.3"}) @hash = @environment.to_hash end %w{name description cookbook_versions}.each do |t| it "should include '#{t}'" do @hash[t].should == @environment.send(t.to_sym) end end it "should include 'json_class'" do @hash["json_class"].should == "Chef::Environment" end it "should include 'chef_type'" do @hash["chef_type"].should == "environment" end end describe "to_json" do before(:each) do @environment.name("spec") @environment.description("Where we run the spec tests") @environment.cookbook_versions({:apt => "= 1.2.3"}) @json = @environment.to_json end %w{name description cookbook_versions}.each do |t| it "should include '#{t}'" do @json.should =~ /"#{t}":#{Regexp.escape(@environment.send(t.to_sym).to_json)}/ end end it "should include 'json_class'" do @json.should =~ /"json_class":"Chef::Environment"/ end it "should include 'chef_type'" do @json.should =~ /"chef_type":"environment"/ end end describe "from_json" do before(:each) do @data = { "name" => "production", "description" => "We are productive", "cookbook_versions" => { "apt" => "= 1.2.3", "god" => ">= 4.2.0", "apache2" => "= 2.0.0" }, "json_class" => "Chef::Environment", "chef_type" => "environment" } @environment = Chef::JSONCompat.from_json(@data.to_json) end it "should return a Chef::Environment" do @environment.should be_a_kind_of(Chef::Environment) end %w{name description cookbook_versions}.each do |t| it "should match '#{t}'" do @environment.send(t.to_sym).should == @data[t] end end end describe "self.validate_cookbook_versions" do before(:each) do @cookbook_versions = { "apt" => "= 1.0.0", "god" => "= 2.0.0", "apache2" => "= 4.2.0" } end it "should validate the version string of each cookbook" do @cookbook_versions.each do |cookbook, version| Chef::Environment.should_receive(:validate_cookbook_version).with(version).and_return true end Chef::Environment.validate_cookbook_versions(@cookbook_versions) end it "should return false if anything other than a hash is passed as the argument" do Chef::Environment.validate_cookbook_versions(Array.new).should == false Chef::Environment.validate_cookbook_versions(42).should == false Chef::Environment.validate_cookbook_versions(Chef::CookbookVersion.new("meta")).should == false Chef::Environment.validate_cookbook_versions("cookbook => 1.2.3").should == false end end describe "self.validate_cookbook_version" do it "should validate correct version numbers" do Chef::Environment.validate_cookbook_version("= 1.2.3").should == true Chef::Environment.validate_cookbook_version(">= 0.0.3").should == true # A lone version is allowed, interpreted as implicit '=' Chef::Environment.validate_cookbook_version("1.2.3").should == true end it "should return false when an invalid version is given" do Chef::Environment.validate_cookbook_version(Chef::CookbookVersion.new("meta")).should == false Chef::Environment.validate_cookbook_version("= 1.2.3a").should == false Chef::Environment.validate_cookbook_version("= 1").should == false Chef::Environment.validate_cookbook_version("= a").should == false Chef::Environment.validate_cookbook_version("= 1.2.3.4").should == false end describe "in solo mode" do before do Chef::Config[:solo] = true end after do Chef::Config[:solo] = false end it "should raise and exception" do lambda { Chef::Environment.validate_cookbook_version("= 1.2.3.4") }.should raise_error Chef::Exceptions::IllegalVersionConstraint, "Environment cookbook version constraints not allowed in chef-solo" end end end describe "when updating from a parameter hash" do before do @environment = Chef::Environment.new end it "updates the name from parameters[:name]" do @environment.update_from_params(:name => "kurrupt") @environment.name.should == "kurrupt" end it "validates the name given in the params" do @environment.update_from_params(:name => "@$%^&*()").should be_false @environment.invalid_fields[:name].should == %q|Option name's value @$%^&*() does not match regular expression /^[\-[:alnum:]_]+$/| end it "updates the description from parameters[:description]" do @environment.update_from_params(:description => "wow, writing your own object mapper is kinda painful") @environment.description.should == "wow, writing your own object mapper is kinda painful" end it "updates cookbook version constraints from the hash in parameters[:cookbook_version_constraints]" do # NOTE: I'm only choosing this (admittedly weird) structure for the hash b/c the better more obvious # one, i.e, {:cookbook_version_constraints => {COOKBOOK_NAME => CONSTRAINT}} is difficult to implement # the way merb does params params = {:name=>"superbowl", :cookbook_version => {"0" => "apache2 ~> 1.0.0", "1" => "nginx < 2.0.0"}} @environment.update_from_params(params) @environment.cookbook_versions.should == {"apache2" => "~> 1.0.0", "nginx" => "< 2.0.0"} end it "validates the cookbook constraints" do params = {:cookbook_version => {"0" => "apache2 >>> 1.0.0"}} @environment.update_from_params(params).should be_false err_msg = @environment.invalid_fields[:cookbook_version]["0"] err_msg.should == "apache2 >>> 1.0.0 is not a valid cookbook constraint" end it "is not valid if the name is not present" do @environment.validate_required_attrs_present.should be_false @environment.invalid_fields[:name].should == "name cannot be empty" end it "is not valid after updating from params if the name is not present" do @environment.update_from_params({}).should be_false @environment.invalid_fields[:name].should == "name cannot be empty" end it "updates default attributes from a JSON string in params[:attributes]" do @environment.update_from_params(:name => "fuuu", :default_attributes => %q|{"fuuu":"RAGE"}|) @environment.default_attributes.should == {"fuuu" => "RAGE"} end it "updates override attributes from a JSON string in params[:attributes]" do @environment.update_from_params(:name => "fuuu", :override_attributes => %q|{"foo":"override"}|) @environment.override_attributes.should == {"foo" => "override"} end end describe "api model" do before(:each) do @rest = mock("Chef::REST") Chef::REST.stub!(:new).and_return(@rest) @query = mock("Chef::Search::Query") Chef::Search::Query.stub!(:new).and_return(@query) end describe "list" do describe "inflated" do it "should return a hash of environment names and objects" do e1 = mock("Chef::Environment", :name => "one") @query.should_receive(:search).with(:environment).and_yield(e1) r = Chef::Environment.list(true) r["one"].should == e1 end end it "should return a hash of environment names and urls" do @rest.should_receive(:get_rest).and_return({ "one" => "http://foo" }) r = Chef::Environment.list r["one"].should == "http://foo" end end end describe "when loading" do describe "in solo mode" do before do Chef::Config[:solo] = true Chef::Config[:environment_path] = '/var/chef/environments' end after do Chef::Config[:solo] = false end it "should get the environment from the environment_path" do File.should_receive(:directory?).with(Chef::Config[:environment_path]).and_return(true) File.should_receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(false) File.should_receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).exactly(2).times.and_return(true) File.should_receive(:readable?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).and_return(true) role_dsl="name \"foo\"\ndescription \"desc\"\n" IO.should_receive(:read).with(File.join(Chef::Config[:environment_path], 'foo.rb')).and_return(role_dsl) Chef::Environment.load('foo') end it "should return a Chef::Environment object from JSON" do File.should_receive(:directory?).with(Chef::Config[:environment_path]).and_return(true) File.should_receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(true) environment_hash = { "name" => "foo", "default_attributes" => { "foo" => { "bar" => 1 } }, "json_class" => "Chef::Environment", "description" => "desc", "chef_type" => "environment" } IO.should_receive(:read).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(JSON.dump(environment_hash)) environment = Chef::Environment.load('foo') environment.should be_a_kind_of(Chef::Environment) environment.name.should == environment_hash['name'] environment.description.should == environment_hash['description'] environment.default_attributes.should == environment_hash['default_attributes'] end it "should return a Chef::Environment object from Ruby DSL" do File.should_receive(:directory?).with(Chef::Config[:environment_path]).and_return(true) File.should_receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(false) File.should_receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).exactly(2).times.and_return(true) File.should_receive(:readable?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).and_return(true) role_dsl="name \"foo\"\ndescription \"desc\"\n" IO.should_receive(:read).with(File.join(Chef::Config[:environment_path], 'foo.rb')).and_return(role_dsl) environment = Chef::Environment.load('foo') environment.should be_a_kind_of(Chef::Environment) environment.name.should == 'foo' environment.description.should == 'desc' end it 'should raise an error if the configured environment_path is invalid' do File.should_receive(:directory?).with(Chef::Config[:environment_path]).and_return(false) lambda { Chef::Environment.load('foo') }.should raise_error Chef::Exceptions::InvalidEnvironmentPath, "Environment path '/var/chef/environments' is invalid" end it 'should raise an error if the file does not exist' do File.should_receive(:directory?).with(Chef::Config[:environment_path]).and_return(true) File.should_receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(false) File.should_receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).and_return(false) lambda { Chef::Environment.load('foo') }.should raise_error Chef::Exceptions::EnvironmentNotFound, "Environment 'foo' could not be loaded from disk" end end end end chef-11.8.2/spec/unit/deprecation_spec.rb0000644000004100000410000000461612254362222020314 0ustar www-datawww-data# # Author:: Serdar Sutay () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/deprecation/warnings' describe Chef::Deprecation do # Support code for Chef::Deprecation def self.class_from_string(str) str.split('::').inject(Object) do |mod, class_name| mod.const_get(class_name) end end module DeprecatedMethods def deprecated_method(value) @value = value end def get_value @value end end class TestClass extend Chef::Deprecation::Warnings include DeprecatedMethods add_deprecation_warnings_for(DeprecatedMethods.instance_methods) end method_snapshot_file = File.join(CHEF_SPEC_DATA, "file-providers-method-snapshot-chef-11-4.json") method_snapshot = JSON.parse(File.open(method_snapshot_file).read()) method_snapshot.each do |class_name, old_methods| class_object = class_from_string(class_name) current_methods = class_object.public_instance_methods.map(&:to_sym) it "defines all methods on #{class_object} that were available in 11.0" do old_methods.each do |old_method| current_methods.should include(old_method.to_sym) end end end context 'deprecation warning messages' do before(:each) do @warning_output = [ ] Chef::Log.stub!(:warn) { |msg| @warning_output << msg } end it 'should be enabled for deprecated methods' do TestClass.new.deprecated_method(10) @warning_output.should_not be_empty end it 'should contain stack trace' do TestClass.new.deprecated_method(10) @warning_output.join("").include?(".rb").should be_true end end it 'deprecated methods should still be called' do test_instance = TestClass.new test_instance.deprecated_method(10) test_instance.get_value.should == 10 end end chef-11.8.2/spec/unit/node_spec.rb0000644000004100000410000007245012254362222016745 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'ostruct' describe Chef::Node do let(:node) { Chef::Node.new() } let(:platform_introspector) { node } it_behaves_like "a platform introspector" it "creates a node and assigns it a name" do node = Chef::Node.build('solo-node') node.name.should == 'solo-node' end it "should validate the name of the node" do lambda{Chef::Node.build('solo node')}.should raise_error(Chef::Exceptions::ValidationFailed) end it "should be sortable" do n1 = Chef::Node.build('alpha') n2 = Chef::Node.build('beta') n3 = Chef::Node.build('omega') [n3, n1, n2].sort.should == [n1, n2, n3] end describe "when the node does not exist on the server" do before do response = OpenStruct.new(:code => '404') exception = Net::HTTPServerException.new("404 not found", response) Chef::Node.stub!(:load).and_raise(exception) node.name("created-node") end it "creates a new node for find_or_create" do Chef::Node.stub!(:new).and_return(node) node.should_receive(:create).and_return(node) node = Chef::Node.find_or_create("created-node") node.name.should == 'created-node' node.should equal(node) end end describe "when the node exists on the server" do before do node.name('existing-node') Chef::Node.stub!(:load).and_return(node) end it "loads the node via the REST API for find_or_create" do Chef::Node.find_or_create('existing-node').should equal(node) end end describe "run_state" do it "is an empty hash" do node.run_state.should respond_to(:keys) node.run_state.should be_empty end end describe "initialize" do it "should default to the '_default' chef_environment" do n = Chef::Node.new n.chef_environment.should == '_default' end end describe "name" do it "should allow you to set a name with name(something)" do lambda { node.name("latte") }.should_not raise_error end it "should return the name with name()" do node.name("latte") node.name.should eql("latte") end it "should always have a string for name" do lambda { node.name(Hash.new) }.should raise_error(ArgumentError) end it "cannot be blank" do lambda { node.name("")}.should raise_error(Chef::Exceptions::ValidationFailed) end it "should not accept name doesn't match /^[\-[:alnum:]_:.]+$/" do lambda { node.name("space in it")}.should raise_error(Chef::Exceptions::ValidationFailed) end end describe "chef_environment" do it "should set an environment with chef_environment(something)" do lambda { node.chef_environment("latte") }.should_not raise_error end it "should return the chef_environment with chef_environment()" do node.chef_environment("latte") node.chef_environment.should == "latte" end it "should disallow non-strings" do lambda { node.chef_environment(Hash.new) }.should raise_error(ArgumentError) lambda { node.chef_environment(42) }.should raise_error(ArgumentError) end it "cannot be blank" do lambda { node.chef_environment("")}.should raise_error(Chef::Exceptions::ValidationFailed) end end describe "attributes" do it "should have attributes" do node.attribute.should be_a_kind_of(Hash) end it "should allow attributes to be accessed by name or symbol directly on node[]" do node.default["locust"] = "something" node[:locust].should eql("something") node["locust"].should eql("something") end it "should return nil if it cannot find an attribute with node[]" do node["secret"].should eql(nil) end it "does not allow you to set an attribute via node[]=" do lambda { node["secret"] = "shush" }.should raise_error(Chef::Exceptions::ImmutableAttributeModification) end it "should allow you to query whether an attribute exists with attribute?" do node.default["locust"] = "something" node.attribute?("locust").should eql(true) node.attribute?("no dice").should eql(false) end it "should let you go deep with attribute?" do node.set["battles"]["people"]["wonkey"] = true node["battles"]["people"].attribute?("wonkey").should == true node["battles"]["people"].attribute?("snozzberry").should == false end it "does not allow you to set an attribute via method_missing" do lambda { node.sunshine = "is bright"}.should raise_error(Chef::Exceptions::ImmutableAttributeModification) end it "should allow you get get an attribute via method_missing" do node.default.sunshine = "is bright" node.sunshine.should eql("is bright") end describe "normal attributes" do it "should allow you to set an attribute with set, without pre-declaring a hash" do node.set[:snoopy][:is_a_puppy] = true node[:snoopy][:is_a_puppy].should == true end it "should allow you to set an attribute with set_unless" do node.set_unless[:snoopy][:is_a_puppy] = false node[:snoopy][:is_a_puppy].should == false end it "should not allow you to set an attribute with set_unless if it already exists" do node.set[:snoopy][:is_a_puppy] = true node.set_unless[:snoopy][:is_a_puppy] = false node[:snoopy][:is_a_puppy].should == true end it "should allow you to set a value after a set_unless" do # this tests for set_unless_present state bleeding between statements CHEF-3806 node.set_unless[:snoopy][:is_a_puppy] = false node.set[:snoopy][:is_a_puppy] = true node[:snoopy][:is_a_puppy].should == true end it "should let you set a value after a 'dangling' set_unless" do # this tests for set_unless_present state bleeding between statements CHEF-3806 node.set[:snoopy][:is_a_puppy] = "what" node.set_unless[:snoopy][:is_a_puppy] node.set[:snoopy][:is_a_puppy] = true node[:snoopy][:is_a_puppy].should == true end it "auto-vivifies attributes created via method syntax" do node.set.fuu.bahrr.baz = "qux" node.fuu.bahrr.baz.should == "qux" end it "should let you use tag as a convience method for the tags attribute" do node.normal['tags'] = ['one', 'two'] node.tag('three', 'four') node['tags'].should == ['one', 'two', 'three', 'four'] end end describe "default attributes" do it "should be set with default, without pre-declaring a hash" do node.default[:snoopy][:is_a_puppy] = true node[:snoopy][:is_a_puppy].should == true end it "should allow you to set with default_unless without pre-declaring a hash" do node.default_unless[:snoopy][:is_a_puppy] = false node[:snoopy][:is_a_puppy].should == false end it "should not allow you to set an attribute with default_unless if it already exists" do node.default[:snoopy][:is_a_puppy] = true node.default_unless[:snoopy][:is_a_puppy] = false node[:snoopy][:is_a_puppy].should == true end it "should allow you to set a value after a default_unless" do # this tests for set_unless_present state bleeding between statements CHEF-3806 node.default_unless[:snoopy][:is_a_puppy] = false node.default[:snoopy][:is_a_puppy] = true node[:snoopy][:is_a_puppy].should == true end it "should allow you to set a value after a 'dangling' default_unless" do # this tests for set_unless_present state bleeding between statements CHEF-3806 node.default[:snoopy][:is_a_puppy] = "what" node.default_unless[:snoopy][:is_a_puppy] node.default[:snoopy][:is_a_puppy] = true node[:snoopy][:is_a_puppy].should == true end it "auto-vivifies attributes created via method syntax" do node.default.fuu.bahrr.baz = "qux" node.fuu.bahrr.baz.should == "qux" end it "accesses force defaults via default!" do node.default![:foo] = "wet bar" node.default[:foo] = "bar" node[:foo].should == "wet bar" end end describe "override attributes" do it "should be set with override, without pre-declaring a hash" do node.override[:snoopy][:is_a_puppy] = true node[:snoopy][:is_a_puppy].should == true end it "should allow you to set with override_unless without pre-declaring a hash" do node.override_unless[:snoopy][:is_a_puppy] = false node[:snoopy][:is_a_puppy].should == false end it "should not allow you to set an attribute with override_unless if it already exists" do node.override[:snoopy][:is_a_puppy] = true node.override_unless[:snoopy][:is_a_puppy] = false node[:snoopy][:is_a_puppy].should == true end it "should allow you to set a value after an override_unless" do # this tests for set_unless_present state bleeding between statements CHEF-3806 node.override_unless[:snoopy][:is_a_puppy] = false node.override[:snoopy][:is_a_puppy] = true node[:snoopy][:is_a_puppy].should == true end it "should allow you to set a value after a 'dangling' override_unless" do # this tests for set_unless_present state bleeding between statements CHEF-3806 node.override_unless[:snoopy][:is_a_puppy] = "what" node.override_unless[:snoopy][:is_a_puppy] node.override[:snoopy][:is_a_puppy] = true node[:snoopy][:is_a_puppy].should == true end it "auto-vivifies attributes created via method syntax" do node.override.fuu.bahrr.baz = "qux" node.fuu.bahrr.baz.should == "qux" end it "sets force_overrides via override!" do node.override![:foo] = "wet bar" node.override[:foo] = "bar" node[:foo].should == "wet bar" end end it "should raise an ArgumentError if you ask for an attribute that doesn't exist via method_missing" do lambda { node.sunshine }.should raise_error(NoMethodError) end it "should allow you to iterate over attributes with each_attribute" do node.default.sunshine = "is bright" node.default.canada = "is a nice place" seen_attributes = Hash.new node.each_attribute do |a,v| seen_attributes[a] = v end seen_attributes.should have_key("sunshine") seen_attributes.should have_key("canada") seen_attributes["sunshine"].should == "is bright" seen_attributes["canada"].should == "is a nice place" end end describe "consuming json" do before do @ohai_data = {:platform => 'foo', :platform_version => 'bar'} end it "consumes the run list portion of a collection of attributes and returns the remainder" do attrs = {"run_list" => [ "role[base]", "recipe[chef::server]" ], "foo" => "bar"} node.consume_run_list(attrs).should == {"foo" => "bar"} node.run_list.should == [ "role[base]", "recipe[chef::server]" ] end it "should overwrites the run list with the run list it consumes" do node.consume_run_list "recipes" => [ "one", "two" ] node.consume_run_list "recipes" => [ "three" ] node.run_list.should == [ "three" ] end it "should not add duplicate recipes from the json attributes" do node.run_list << "one" node.consume_run_list "recipes" => [ "one", "two", "three" ] node.run_list.should == [ "one", "two", "three" ] end it "doesn't change the run list if no run_list is specified in the json" do node.run_list << "role[database]" node.consume_run_list "foo" => "bar" node.run_list.should == ["role[database]"] end it "raises an exception if you provide both recipe and run_list attributes, since this is ambiguous" do lambda { node.consume_run_list "recipes" => "stuff", "run_list" => "other_stuff" }.should raise_error(Chef::Exceptions::AmbiguousRunlistSpecification) end it "should add json attributes to the node" do node.consume_external_attrs(@ohai_data, {"one" => "two", "three" => "four"}) node.one.should eql("two") node.three.should eql("four") end it "should set the tags attribute to an empty array if it is not already defined" do node.consume_external_attrs(@ohai_data, {}) node.tags.should eql([]) end it "should not set the tags attribute to an empty array if it is already defined" do node.normal[:tags] = [ "radiohead" ] node.consume_external_attrs(@ohai_data, {}) node.tags.should eql([ "radiohead" ]) end it "deep merges attributes instead of overwriting them" do node.consume_external_attrs(@ohai_data, "one" => {"two" => {"three" => "four"}}) node.one.to_hash.should == {"two" => {"three" => "four"}} node.consume_external_attrs(@ohai_data, "one" => {"abc" => "123"}) node.consume_external_attrs(@ohai_data, "one" => {"two" => {"foo" => "bar"}}) node.one.to_hash.should == {"two" => {"three" => "four", "foo" => "bar"}, "abc" => "123"} end it "gives attributes from JSON priority when deep merging" do node.consume_external_attrs(@ohai_data, "one" => {"two" => {"three" => "four"}}) node.one.to_hash.should == {"two" => {"three" => "four"}} node.consume_external_attrs(@ohai_data, "one" => {"two" => {"three" => "forty-two"}}) node.one.to_hash.should == {"two" => {"three" => "forty-two"}} end end describe "preparing for a chef client run" do before do @ohai_data = {:platform => 'foobuntu', :platform_version => '23.42'} end it "sets its platform according to platform detection" do node.consume_external_attrs(@ohai_data, {}) node.automatic_attrs[:platform].should == 'foobuntu' node.automatic_attrs[:platform_version].should == '23.42' end it "consumes the run list from provided json attributes" do node.consume_external_attrs(@ohai_data, {"run_list" => ['recipe[unicorn]']}) node.run_list.should == ['recipe[unicorn]'] end it "saves non-runlist json attrs for later" do expansion = Chef::RunList::RunListExpansion.new('_default', []) node.run_list.stub!(:expand).and_return(expansion) node.consume_external_attrs(@ohai_data, {"foo" => "bar"}) node.expand! node.normal_attrs.should == {"foo" => "bar", "tags" => []} end end describe "when expanding its run list and merging attributes" do before do @environment = Chef::Environment.new.tap do |e| e.name('rspec_env') e.default_attributes("env default key" => "env default value") e.override_attributes("env override key" => "env override value") end Chef::Environment.should_receive(:load).with("rspec_env").and_return(@environment) @expansion = Chef::RunList::RunListExpansion.new("rspec_env", []) node.chef_environment("rspec_env") node.run_list.stub!(:expand).and_return(@expansion) end it "sets the 'recipes' automatic attribute to the recipes in the expanded run_list" do @expansion.recipes << 'recipe[chef::client]' << 'recipe[nginx::default]' node.expand! node.automatic_attrs[:recipes].should == ['recipe[chef::client]', 'recipe[nginx::default]'] end it "sets the 'roles' automatic attribute to the expanded role list" do @expansion.instance_variable_set(:@applied_roles, {'arf' => nil, 'countersnark' => nil}) node.expand! node.automatic_attrs[:roles].sort.should == ['arf', 'countersnark'] end it "applies default attributes from the environment as environment defaults" do node.expand! node.attributes.env_default["env default key"].should == "env default value" end it "applies override attributes from the environment as env overrides" do node.expand! node.attributes.env_override["env override key"].should == "env override value" end it "applies default attributes from roles as role defaults" do @expansion.default_attrs["role default key"] = "role default value" node.expand! node.attributes.role_default["role default key"].should == "role default value" end it "applies override attributes from roles as role overrides" do @expansion.override_attrs["role override key"] = "role override value" node.expand! node.attributes.role_override["role override key"].should == "role override value" end end describe "when querying for recipes in the run list" do context "when a recipe is in the top level run list" do before do node.run_list << "recipe[nginx::module]" end it "finds the recipe" do node.recipe?("nginx::module").should be_true end it "does not find a recipe not in the run list" do node.recipe?("nginx::other_module").should be_false end end context "when a recipe is in the expanded run list only" do before do node.run_list << "role[base]" node.automatic_attrs[:recipes] = [ "nginx::module" ] end it "finds a recipe in the expanded run list" do node.recipe?("nginx::module").should be_true end it "does not find a recipe that's not in the run list" do node.recipe?("nginx::other_module").should be_false end end end describe "when clearing computed state at the beginning of a run" do before do node.default[:foo] = "default" node.normal[:foo] = "normal" node.override[:foo] = "override" node.reset_defaults_and_overrides end it "removes default attributes" do node.default.should be_empty end it "removes override attributes" do node.override.should be_empty end it "leaves normal level attributes untouched" do node[:foo].should == "normal" end end describe "when merging environment attributes" do before do node.chef_environment = "rspec" @expansion = Chef::RunList::RunListExpansion.new("rspec", []) @expansion.default_attrs.replace({:default => "from role", :d_role => "role only"}) @expansion.override_attrs.replace({:override => "from role", :o_role => "role only"}) @environment = Chef::Environment.new @environment.default_attributes = {:default => "from env", :d_env => "env only" } @environment.override_attributes = {:override => "from env", :o_env => "env only"} Chef::Environment.stub!(:load).and_return(@environment) node.apply_expansion_attributes(@expansion) end it "does not nuke role-only default attrs" do node[:d_role].should == "role only" end it "does not nuke role-only override attrs" do node[:o_role].should == "role only" end it "does not nuke env-only default attrs" do node[:o_env].should == "env only" end it "does not nuke role-only override attrs" do node[:o_env].should == "env only" end it "gives role defaults precedence over env defaults" do node[:default].should == "from role" end it "gives env overrides precedence over role overrides" do node[:override].should == "from env" end end describe "when evaluating attributes files" do before do @cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) @cookbook_loader = Chef::CookbookLoader.new(@cookbook_repo) @cookbook_loader.load_cookbooks @cookbook_collection = Chef::CookbookCollection.new(@cookbook_loader.cookbooks_by_name) @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(node, @cookbook_collection, @events) node.include_attribute("openldap::default") node.include_attribute("openldap::smokey") end it "sets attributes from the files" do node.ldap_server.should eql("ops1prod") node.ldap_basedn.should eql("dc=hjksolutions,dc=com") node.ldap_replication_password.should eql("forsure") node.smokey.should eql("robinson") end it "gives a sensible error when attempting to load a missing attributes file" do lambda { node.include_attribute("nope-this::doesnt-exist") }.should raise_error(Chef::Exceptions::CookbookNotFound) end end describe "roles" do it "should allow you to query whether or not it has a recipe applied with role?" do node.run_list << "role[sunrise]" node.role?("sunrise").should eql(true) node.role?("not at home").should eql(false) end it "should allow you to set roles with arguments" do node.run_list << "role[one]" node.run_list << "role[two]" node.role?("one").should eql(true) node.role?("two").should eql(true) end end describe "run_list" do it "should have a Chef::RunList of recipes and roles that should be applied" do node.run_list.should be_a_kind_of(Chef::RunList) end it "should allow you to query the run list with arguments" do node.run_list "recipe[baz]" node.run_list?("recipe[baz]").should eql(true) end it "should allow you to set the run list with arguments" do node.run_list "recipe[baz]", "role[foo]" node.run_list?("recipe[baz]").should eql(true) node.run_list?("role[foo]").should eql(true) end end describe "from file" do it "should load a node from a ruby file" do node.from_file(File.expand_path(File.join(CHEF_SPEC_DATA, "nodes", "test.rb"))) node.name.should eql("test.example.com-short") node.sunshine.should eql("in") node.something.should eql("else") node.run_list.should == ["operations-master", "operations-monitoring"] end it "should raise an exception if the file cannot be found or read" do lambda { node.from_file("/tmp/monkeydiving") }.should raise_error(IOError) end end describe "update_from!" do before(:each) do node.name("orig") node.chef_environment("dev") node.default_attrs = { "one" => { "two" => "three", "four" => "five", "eight" => "nine" } } node.override_attrs = { "one" => { "two" => "three", "four" => "six" } } node.normal_attrs = { "one" => { "two" => "seven" } } node.run_list << "role[marxist]" node.run_list << "role[leninist]" node.run_list << "recipe[stalinist]" @example = Chef::Node.new() @example.name("newname") @example.chef_environment("prod") @example.default_attrs = { "alpha" => { "bravo" => "charlie", "delta" => "echo" } } @example.override_attrs = { "alpha" => { "bravo" => "foxtrot", "delta" => "golf" } } @example.normal_attrs = { "alpha" => { "bravo" => "hotel" } } @example.run_list << "role[comedy]" @example.run_list << "role[drama]" @example.run_list << "recipe[mystery]" end it "allows update of everything except name" do node.update_from!(@example) node.name.should == "orig" node.chef_environment.should == @example.chef_environment node.default_attrs.should == @example.default_attrs node.override_attrs.should == @example.override_attrs node.normal_attrs.should == @example.normal_attrs node.run_list.should == @example.run_list end it "should not update the name of the node" do node.should_not_receive(:name).with(@example.name) node.update_from!(@example) end end describe "to_hash" do it "should serialize itself as a hash" do node.chef_environment("dev") node.default_attrs = { "one" => { "two" => "three", "four" => "five", "eight" => "nine" } } node.override_attrs = { "one" => { "two" => "three", "four" => "six" } } node.normal_attrs = { "one" => { "two" => "seven" } } node.run_list << "role[marxist]" node.run_list << "role[leninist]" node.run_list << "recipe[stalinist]" h = node.to_hash h["one"]["two"].should == "three" h["one"]["four"].should == "six" h["one"]["eight"].should == "nine" h["role"].should be_include("marxist") h["role"].should be_include("leninist") h["run_list"].should be_include("role[marxist]") h["run_list"].should be_include("role[leninist]") h["run_list"].should be_include("recipe[stalinist]") h["chef_environment"].should == "dev" end end describe "converting to or from json" do it "should serialize itself as json", :json => true do node.from_file(File.expand_path("nodes/test.example.com.rb", CHEF_SPEC_DATA)) json = Chef::JSONCompat.to_json(node) json.should =~ /json_class/ json.should =~ /name/ json.should =~ /chef_environment/ json.should =~ /normal/ json.should =~ /default/ json.should =~ /override/ json.should =~ /run_list/ end it 'should serialize valid json with a run list', :json => true do #This test came about because activesupport mucks with Chef json serialization #Test should pass with and without Activesupport node.run_list << {"type" => "role", "name" => 'Cthulu'} node.run_list << {"type" => "role", "name" => 'Hastur'} json = Chef::JSONCompat.to_json(node) json.should =~ /\"run_list\":\[\"role\[Cthulu\]\",\"role\[Hastur\]\"\]/ end it "merges the override components into a combined override object" do node.attributes.role_override["role override"] = "role override" node.attributes.env_override["env override"] = "env override" node_for_json = node.for_json node_for_json["override"]["role override"].should == "role override" node_for_json["override"]["env override"].should == "env override" end it "merges the default components into a combined default object" do node.attributes.role_default["role default"] = "role default" node.attributes.env_default["env default"] = "env default" node_for_json = node.for_json node_for_json["default"]["role default"].should == "role default" node_for_json["default"]["env default"].should == "env default" end it "should deserialize itself from json", :json => true do node.from_file(File.expand_path("nodes/test.example.com.rb", CHEF_SPEC_DATA)) json = Chef::JSONCompat.to_json(node) serialized_node = Chef::JSONCompat.from_json(json) serialized_node.should be_a_kind_of(Chef::Node) serialized_node.name.should eql(node.name) serialized_node.chef_environment.should eql(node.chef_environment) node.each_attribute do |k,v| serialized_node[k].should eql(v) end serialized_node.run_list.should == node.run_list end end describe "to_s" do it "should turn into a string like node[name]" do node.name("airplane") node.to_s.should eql("node[airplane]") end end describe "api model" do before(:each) do @rest = mock("Chef::REST") Chef::REST.stub!(:new).and_return(@rest) @query = mock("Chef::Search::Query") Chef::Search::Query.stub!(:new).and_return(@query) end describe "list" do describe "inflated" do it "should return a hash of node names and objects" do n1 = mock("Chef::Node", :name => "one") @query.should_receive(:search).with(:node).and_yield(n1) r = Chef::Node.list(true) r["one"].should == n1 end end it "should return a hash of node names and urls" do @rest.should_receive(:get_rest).and_return({ "one" => "http://foo" }) r = Chef::Node.list r["one"].should == "http://foo" end end describe "load" do it "should load a node by name" do @rest.should_receive(:get_rest).with("nodes/monkey").and_return("foo") Chef::Node.load("monkey").should == "foo" end end describe "destroy" do it "should destroy a node" do @rest.should_receive(:delete_rest).with("nodes/monkey").and_return("foo") node.name("monkey") node.destroy end end describe "save" do it "should update a node if it already exists" do node.name("monkey") @rest.should_receive(:put_rest).with("nodes/monkey", node).and_return("foo") node.save end it "should not try and create if it can update" do node.name("monkey") @rest.should_receive(:put_rest).with("nodes/monkey", node).and_return("foo") @rest.should_not_receive(:post_rest) node.save end it "should create if it cannot update" do node.name("monkey") exception = mock("404 error", :code => "404") @rest.should_receive(:put_rest).and_raise(Net::HTTPServerException.new("foo", exception)) @rest.should_receive(:post_rest).with("nodes", node) node.save end describe "when whyrun mode is enabled" do before do Chef::Config[:why_run] = true end after do Chef::Config[:why_run] = false end it "should not save" do node.name("monkey") @rest.should_not_receive(:put_rest) @rest.should_not_receive(:post_rest) node.save end end end end end chef-11.8.2/spec/unit/cookbook_site_streaming_uploader.rb0000644000004100000410000001502712254362222023601 0ustar www-datawww-data# # Author:: Xabier de Zuazo (xabier@onddo.com) # Copyright:: Copyright (c) 2013 Onddo Labs, SL. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/cookbook_site_streaming_uploader' class FakeTempfile def initialize(basename) @basename = basename end def close end def path "#{@basename}.ZZZ" end end describe Chef::CookbookSiteStreamingUploader do describe "create_build_dir" do before(:each) do @cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, 'cookbooks')) @loader = Chef::CookbookLoader.new(@cookbook_repo) @loader.load_cookbooks File.stub(:unlink).and_return() end it "should create the cookbook tmp dir" do cookbook = @loader[:openldap] files_count = Dir.glob(File.join(@cookbook_repo, cookbook.name.to_s, '**', '*'), File::FNM_DOTMATCH).count { |file| File.file?(file) } Tempfile.should_receive(:new).with("chef-#{cookbook.name}-build").and_return(FakeTempfile.new("chef-#{cookbook.name}-build")) FileUtils.should_receive(:mkdir_p).exactly(files_count + 1).times FileUtils.should_receive(:cp).exactly(files_count).times Chef::CookbookSiteStreamingUploader.create_build_dir(cookbook) end end # create_build_dir describe "make_request" do before(:each) do @uri = "http://cookbooks.dummy.com/api/v1/cookbooks" @secret_filename = File.join(CHEF_SPEC_DATA, 'ssl/private_key.pem') @rsa_key = File.read(@secret_filename) response = Net::HTTPResponse.new('1.0', '200', 'OK') Net::HTTP.any_instance.stub(:request).and_return(response) end it "should send an http request" do Net::HTTP.any_instance.should_receive(:request) Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename) end it "should read the private key file" do File.should_receive(:read).with(@secret_filename).and_return(@rsa_key) Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename) end it "should add the authentication signed header" do Mixlib::Authentication::SigningObject.any_instance.should_receive(:sign).and_return({}) Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename) end it "should be able to send post requests" do post = Net::HTTP::Post.new(@uri, {}) Net::HTTP::Post.should_receive(:new).once.and_return(post) Net::HTTP::Put.should_not_receive(:new) Net::HTTP::Get.should_not_receive(:new) Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename) end it "should be able to send put requests" do put = Net::HTTP::Put.new(@uri, {}) Net::HTTP::Post.should_not_receive(:new) Net::HTTP::Put.should_receive(:new).once.and_return(put) Net::HTTP::Get.should_not_receive(:new) Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, 'bill', @secret_filename) end it "should be able to receive files to attach as argument" do Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, 'bill', @secret_filename, { :myfile => File.new(File.join(CHEF_SPEC_DATA, 'config.rb')), # a dummy file }) end it "should be able to receive strings to attach as argument" do Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, 'bill', @secret_filename, { :mystring => 'Lorem ipsum', }) end it "should be able to receive strings and files as argument at the same time" do Chef::CookbookSiteStreamingUploader.make_request(:put, @uri, 'bill', @secret_filename, { :myfile1 => File.new(File.join(CHEF_SPEC_DATA, 'config.rb')), :mystring1 => 'Lorem ipsum', :myfile2 => File.new(File.join(CHEF_SPEC_DATA, 'config.rb')), :mystring2 => 'Dummy text', }) end end # make_request describe "StreamPart" do before(:each) do @file = File.new(File.join(CHEF_SPEC_DATA, 'config.rb')) @stream_part = Chef::CookbookSiteStreamingUploader::StreamPart.new(@file, File.size(@file)) end it "should create a StreamPart" do @stream_part.should be_instance_of(Chef::CookbookSiteStreamingUploader::StreamPart) end it "should expose its size" do @stream_part.size.should eql(File.size(@file)) end it "should read with offset and how_much" do content = @file.read(4) @file.rewind @stream_part.read(0, 4).should eql(content) end end # StreamPart describe "StringPart" do before(:each) do @str = 'What a boring string' @string_part = Chef::CookbookSiteStreamingUploader::StringPart.new(@str) end it "should create a StringPart" do @string_part.should be_instance_of(Chef::CookbookSiteStreamingUploader::StringPart) end it "should expose its size" do @string_part.size.should eql(@str.size) end it "should read with offset and how_much" do @string_part.read(2, 4).should eql(@str[2, 4]) end end # StringPart describe "MultipartStream" do before(:each) do @string1 = "stream1" @string2 = "stream2" @stream1 = Chef::CookbookSiteStreamingUploader::StringPart.new(@string1) @stream2 = Chef::CookbookSiteStreamingUploader::StringPart.new(@string2) @parts = [ @stream1, @stream2 ] @multipart_stream = Chef::CookbookSiteStreamingUploader::MultipartStream.new(@parts) end it "should create a MultipartStream" do @multipart_stream.should be_instance_of(Chef::CookbookSiteStreamingUploader::MultipartStream) end it "should expose its size" do @multipart_stream.size.should eql(@stream1.size + @stream2.size) end it "should read with how_much" do @multipart_stream.read(10).should eql("#{@string1}#{@string2}"[0, 10]) end it "should read receiving destination buffer as second argument (CHEF-4456: Ruby 2 compat)" do dst_buf = '' @multipart_stream.read(10, dst_buf) dst_buf.should eql("#{@string1}#{@string2}"[0, 10]) end end # MultipartStream end chef-11.8.2/spec/unit/resource_collection/0000755000004100000410000000000012254362222020513 5ustar www-datawww-datachef-11.8.2/spec/unit/resource_collection/stepable_iterator_spec.rb0000644000004100000410000000770712254362222025575 0ustar www-datawww-data# Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 Daniel DeLeo # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::ResourceCollection::StepableIterator do CRSI = Chef::ResourceCollection::StepableIterator it "has an empty array for its collection by default" do CRSI.new.collection.should == [] end describe "doing basic iteration" do before do @simple_collection = [1,2,3,4] @iterator = CRSI.for_collection(@simple_collection) end it "re-initializes the instance with a collection" do @iterator.collection.should equal(@simple_collection) @iterator.size.should == 4 end it "iterates over the collection" do sum = 0 @iterator.each do |int| sum += int end sum.should == 10 end it "iterates over the collection with each_index" do collected_by_index = [] @iterator.each_index do |idx| collected_by_index << @simple_collection[idx] end collected_by_index.should == @simple_collection collected_by_index.should_not equal(@simple_collection) end it "iterates over the collection with index and element" do collected = {} @iterator.each_with_index do |element, index| collected[index] = element end collected.should == {0=>1, 1=>2, 2=>3, 3=>4} end end describe "pausing and resuming iteration" do before do @collection = [] @snitch_var = nil @collection << lambda { @snitch_var = 23 } @collection << lambda { @iterator.pause } @collection << lambda { @snitch_var = 42 } @iterator = CRSI.for_collection(@collection) @iterator.each { |proc| proc.call } end it "allows the iteration to be paused" do @snitch_var.should == 23 end it "allows the iteration to be resumed" do @snitch_var.should == 23 @iterator.resume @snitch_var.should == 42 end it "allows iteration to be rewound" do @iterator.skip_back(2) @iterator.resume @snitch_var.should == 23 @iterator.resume @snitch_var.should == 42 end it "allows iteration to be fast forwarded" do @iterator.skip_forward @iterator.resume @snitch_var.should == 23 end it "allows iteration to be rewound" do @snitch_var = nil @iterator.rewind @iterator.position.should == 0 @iterator.resume @snitch_var.should == 23 end it "allows iteration to be stepped" do @snitch_var = nil @iterator.rewind @iterator.step @iterator.position.should == 1 @snitch_var.should == 23 end it "doesn't step if there are no more steps" do @iterator.step.should == 3 lambda {@iterator.step}.should_not raise_error @iterator.step.should be_nil end it "allows the iteration to start by being stepped" do @snitch_var = nil @iterator = CRSI.for_collection(@collection) @iterator.iterate_on(:element) { |proc| proc.call } @iterator.step @iterator.position.should == 1 @snitch_var.should == 23 end it "should work correctly when elements are added to the collection during iteration" do @collection.insert(2, lambda { @snitch_var = 815}) @collection.insert(3, lambda { @iterator.pause }) @iterator.resume @snitch_var.should == 815 @iterator.resume @snitch_var.should == 42 end end end chef-11.8.2/spec/unit/rest/0000755000004100000410000000000012254362222015426 5ustar www-datawww-datachef-11.8.2/spec/unit/rest/auth_credentials_spec.rb0000644000004100000410000003136112254362222022307 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Brown () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'uri' require 'net/https' KEY_DOT_PEM=<<-END_RSA_KEY -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA49TA0y81ps0zxkOpmf5V4/c4IeR5yVyQFpX3JpxO4TquwnRh 8VSUhrw8kkTLmB3cS39Db+3HadvhoqCEbqPE6915kXSuk/cWIcNozujLK7tkuPEy YVsyTioQAddSdfe+8EhQVf3oHxaKmUd6waXrWqYCnhxgOjxocenREYNhZ/OETIei PbOku47vB4nJK/0GhKBytL2XnsRgfKgDxf42BqAi1jglIdeq8lAWZNF9TbNBU21A O1iuT7Pm6LyQujhggPznR5FJhXKRUARXBJZawxpGV4dGtdcahwXNE4601aXPra+x PcRd2puCNoEDBzgVuTSsLYeKBDMSfs173W1QYwIDAQABAoIBAGF05q7vqOGbMaSD 2Q7YbuE/JTHKTBZIlBI1QC2x+0P5GDxyEFttNMOVzcs7xmNhkpRw8eX1LrInrpMk WsIBKAFFEfWYlf0RWtRChJjNl+szE9jQxB5FJnWtJH/FHa78tR6PsF24aQyzVcJP g0FGujBihwgfV0JSCNOBkz8MliQihjQA2i8PGGmo4R4RVzGfxYKTIq9vvRq/+QEa Q4lpVLoBqnENpnY/9PTl6JMMjW2b0spbLjOPVwDaIzXJ0dChjNXo15K5SHI5mALJ I5gN7ODGb8PKUf4619ez194FXq+eob5YJdilTFKensIUvt3YhP1ilGMM+Chi5Vi/ /RCTw3ECgYEA9jTw4wv9pCswZ9wbzTaBj9yZS3YXspGg26y6Ohq3ZmvHz4jlT6uR xK+DDcUiK4072gci8S4Np0fIVS7q6ivqcOdzXPrTF5/j+MufS32UrBbUTPiM1yoO ECcy+1szl/KoLEV09bghPbvC58PFSXV71evkaTETYnA/F6RK12lEepcCgYEA7OSy bsMrGDVU/MKJtwqyGP9ubA53BorM4Pp9VVVSCrGGVhb9G/XNsjO5wJC8J30QAo4A s59ZzCpyNRy046AB8jwRQuSwEQbejSdeNgQGXhZ7aIVUtuDeFFdaIz/zjVgxsfj4 DPOuzieMmJ2MLR4F71ocboxNoDI7xruPSE8dDhUCgYA3vx732cQxgtHwAkeNPJUz dLiE/JU7CnxIoSB9fYUfPLI+THnXgzp7NV5QJN2qzMzLfigsQcg3oyo6F2h7Yzwv GkjlualIRRzCPaCw4Btkp7qkPvbs1QngIHALt8fD1N69P3DPHkTwjG4COjKWgnJq qoHKS6Fe/ZlbigikI6KsuwKBgQCTlSLoyGRHr6oj0hqz01EDK9ciMJzMkZp0Kvn8 OKxlBxYW+jlzut4MQBdgNYtS2qInxUoAnaz2+hauqhSzntK3k955GznpUatCqx0R b857vWviwPX2/P6+E3GPdl8IVsKXCvGWOBZWTuNTjQtwbDzsUepWoMgXnlQJSn5I YSlLxQKBgQD16Gw9kajpKlzsPa6XoQeGmZALT6aKWJQlrKtUQIrsIWM0Z6eFtX12 2jjHZ0awuCQ4ldqwl8IfRogWMBkHOXjTPVK0YKWWlxMpD/5+bGPARa5fir8O1Zpo Y6S6MeZ69Rp89ma4ttMZ+kwi1+XyHqC/dlcVRW42Zl5Dc7BALRlJjQ== -----END RSA PRIVATE KEY----- END_RSA_KEY describe Chef::REST::AuthCredentials do before do @key_file_fixture = CHEF_SPEC_DATA + '/ssl/private_key.pem' @key = OpenSSL::PKey::RSA.new(IO.read(@key_file_fixture).strip) @auth_credentials = Chef::REST::AuthCredentials.new("client-name", @key) end it "has a client name" do @auth_credentials.client_name.should == "client-name" end it "loads the private key when initialized with the path to the key" do @auth_credentials.key.should respond_to(:private_encrypt) @auth_credentials.key.to_s.should == KEY_DOT_PEM end describe "when loading the private key" do it "strips extra whitespace before checking the key" do key_file_fixture = CHEF_SPEC_DATA + '/ssl/private_key_with_whitespace.pem' lambda {Chef::REST::AuthCredentials.new("client-name", @key_file_fixture)}.should_not raise_error end end describe "generating signature headers for a request" do before do @request_time = Time.at(1270920860) @request_params = {:http_method => :POST, :path => "/clients", :body => '{"some":"json"}', :host => "localhost"} end it "generates signature headers for the request" do Time.stub!(:now).and_return(@request_time) actual = @auth_credentials.signature_headers(@request_params) actual["HOST"].should == "localhost" actual["X-OPS-AUTHORIZATION-1"].should == "kBssX1ENEwKtNYFrHElN9vYGWS7OeowepN9EsYc9csWfh8oUovryPKDxytQ/" actual["X-OPS-AUTHORIZATION-2"].should == "Wc2/nSSyxdWJjjfHzrE+YrqNQTaArOA7JkAf5p75eTUonCWcvNPjFrZVgKGS" actual["X-OPS-AUTHORIZATION-3"].should == "yhzHJQh+lcVA9wwARg5Hu9q+ddS8xBOdm3Vp5atl5NGHiP0loiigMYvAvzPO" actual["X-OPS-AUTHORIZATION-4"].should == "r9853eIxwYMhn5hLGhAGFQznJbE8+7F/lLU5Zmk2t2MlPY8q3o1Q61YD8QiJ" actual["X-OPS-AUTHORIZATION-5"].should == "M8lIt53ckMyUmSU0DDURoiXLVkE9mag/6Yq2tPNzWq2AdFvBqku9h2w+DY5k" actual["X-OPS-AUTHORIZATION-6"].should == "qA5Rnzw5rPpp3nrWA9jKkPw4Wq3+4ufO2Xs6w7GCjA==" actual["X-OPS-CONTENT-HASH"].should == "1tuzs5XKztM1ANrkGNPah6rW9GY=" actual["X-OPS-SIGN"].should =~ %r{(version=1\.0)|(algorithm=sha1;version=1.0;)} actual["X-OPS-TIMESTAMP"].should == "2010-04-10T17:34:20Z" actual["X-OPS-USERID"].should == "client-name" end describe "when configured for version 1.1 of the authn protocol" do before do Chef::Config[:authentication_protocol_version] = "1.1" end after do Chef::Config[:authentication_protocol_version] = "1.0" end it "generates the correct signature for version 1.1" do Time.stub!(:now).and_return(@request_time) actual = @auth_credentials.signature_headers(@request_params) actual["HOST"].should == "localhost" actual["X-OPS-CONTENT-HASH"].should == "1tuzs5XKztM1ANrkGNPah6rW9GY=" actual["X-OPS-SIGN"].should == "algorithm=sha1;version=1.1;" actual["X-OPS-TIMESTAMP"].should == "2010-04-10T17:34:20Z" actual["X-OPS-USERID"].should == "client-name" # mixlib-authN will test the actual signature stuff for each version of # the protocol so we won't test it again here. end end end end describe Chef::REST::RESTRequest do def new_request(method=nil) method ||= :POST Chef::REST::RESTRequest.new(method, @url, @req_body, @headers) end before do @auth_credentials = Chef::REST::AuthCredentials.new("client-name", CHEF_SPEC_DATA + '/ssl/private_key.pem') @url = URI.parse("http://chef.example.com:4000/?q=chef_is_awesome") @req_body = '{"json_data":"as_a_string"}' @headers = {"Content-type" =>"application/json", "Accept"=>"application/json", "Accept-Encoding" => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE} @request = Chef::REST::RESTRequest.new(:POST, @url, @req_body, @headers) end it "stores the url it was created with" do @request.url.should == @url end it "stores the HTTP method" do @request.method.should == :POST end it "adds the chef version header" do @request.headers.should == @headers.merge("X-Chef-Version" => ::Chef::VERSION) end describe "configuring the HTTP request" do it "configures GET requests" do @req_body = nil rest_req = new_request(:GET) rest_req.http_request.should be_a_kind_of(Net::HTTP::Get) rest_req.http_request.path.should == "/?q=chef_is_awesome" rest_req.http_request.body.should be_nil end it "configures POST requests, including the body" do @request.http_request.should be_a_kind_of(Net::HTTP::Post) @request.http_request.path.should == "/?q=chef_is_awesome" @request.http_request.body.should == @req_body end it "configures PUT requests, including the body" do rest_req = new_request(:PUT) rest_req.http_request.should be_a_kind_of(Net::HTTP::Put) rest_req.http_request.path.should == "/?q=chef_is_awesome" rest_req.http_request.body.should == @req_body end it "configures DELETE requests" do rest_req = new_request(:DELETE) rest_req.http_request.should be_a_kind_of(Net::HTTP::Delete) rest_req.http_request.path.should == "/?q=chef_is_awesome" rest_req.http_request.body.should be_nil end it "configures HTTP basic auth" do @url = URI.parse("http://homie:theclown@chef.example.com:4000/?q=chef_is_awesome") rest_req = new_request(:GET) rest_req.http_request.to_hash["authorization"].should == ["Basic aG9taWU6dGhlY2xvd24="] end end describe "configuring the HTTP client" do it "configures the HTTP client for the host and port" do http_client = new_request.http_client http_client.address.should == "chef.example.com" http_client.port.should == 4000 end it "configures the HTTP client with the read timeout set in the config file" do Chef::Config[:rest_timeout] = 9001 new_request.http_client.read_timeout.should == 9001 end describe "for proxy" do before do Chef::Config[:http_proxy] = "http://proxy.example.com:3128" Chef::Config[:https_proxy] = "http://sproxy.example.com:3129" Chef::Config[:http_proxy_user] = nil Chef::Config[:http_proxy_pass] = nil Chef::Config[:https_proxy_user] = nil Chef::Config[:https_proxy_pass] = nil Chef::Config[:no_proxy] = nil end after do Chef::Config[:http_proxy] = nil Chef::Config[:https_proxy] = nil Chef::Config[:http_proxy_user] = nil Chef::Config[:http_proxy_pass] = nil Chef::Config[:https_proxy_user] = nil Chef::Config[:https_proxy_pass] = nil Chef::Config[:no_proxy] = nil end describe "with :no_proxy nil" do it "configures the proxy address and port when using http scheme" do http_client = new_request.http_client http_client.proxy?.should == true http_client.proxy_address.should == "proxy.example.com" http_client.proxy_port.should == 3128 http_client.proxy_user.should be_nil http_client.proxy_pass.should be_nil end it "configures the proxy address and port when using https scheme" do @url.scheme = "https" http_client = new_request.http_client http_client.proxy?.should == true http_client.proxy_address.should == "sproxy.example.com" http_client.proxy_port.should == 3129 http_client.proxy_user.should be_nil http_client.proxy_pass.should be_nil end end describe "with :no_proxy set" do before do Chef::Config[:no_proxy] = "10.*,*.example.com" end it "does not configure the proxy address and port when using http scheme" do http_client = new_request.http_client http_client.proxy?.should == false http_client.proxy_address.should be_nil http_client.proxy_port.should be_nil http_client.proxy_user.should be_nil http_client.proxy_pass.should be_nil end it "does not configure the proxy address and port when using https scheme" do @url.scheme = "https" http_client = new_request.http_client http_client.proxy?.should == false http_client.proxy_address.should be_nil http_client.proxy_port.should be_nil http_client.proxy_user.should be_nil http_client.proxy_pass.should be_nil end end describe "with :http_proxy_user and :http_proxy_pass set" do before do Chef::Config[:http_proxy_user] = "homie" Chef::Config[:http_proxy_pass] = "theclown" end after do Chef::Config[:http_proxy_user] = nil Chef::Config[:http_proxy_pass] = nil end it "configures the proxy user and pass when using http scheme" do http_client = new_request.http_client http_client.proxy?.should == true http_client.proxy_user.should == "homie" http_client.proxy_pass.should == "theclown" end it "does not configure the proxy user and pass when using https scheme" do @url.scheme = "https" http_client = new_request.http_client http_client.proxy?.should == true http_client.proxy_user.should be_nil http_client.proxy_pass.should be_nil end end describe "with :https_proxy_user and :https_proxy_pass set" do before do Chef::Config[:https_proxy_user] = "homie" Chef::Config[:https_proxy_pass] = "theclown" end after do Chef::Config[:https_proxy_user] = nil Chef::Config[:https_proxy_pass] = nil end it "does not configure the proxy user and pass when using http scheme" do http_client = new_request.http_client http_client.proxy?.should == true http_client.proxy_user.should be_nil http_client.proxy_pass.should be_nil end it "configures the proxy user and pass when using https scheme" do @url.scheme = "https" http_client = new_request.http_client http_client.proxy?.should == true http_client.proxy_user.should == "homie" http_client.proxy_pass.should == "theclown" end end end end end chef-11.8.2/spec/unit/application/0000755000004100000410000000000012254362222016754 5ustar www-datawww-datachef-11.8.2/spec/unit/application/server_spec.rb0000644000004100000410000000000012254362222021607 0ustar www-datawww-datachef-11.8.2/spec/unit/application/solo_spec.rb0000644000004100000410000001032712254362222021272 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'spec_helper' describe Chef::Application::Solo do before do @app = Chef::Application::Solo.new @app.stub!(:configure_opt_parser).and_return(true) @app.stub!(:configure_chef).and_return(true) @app.stub!(:configure_logging).and_return(true) Chef::Config[:recipe_url] = false Chef::Config[:json_attribs] = false Chef::Config[:solo] = true end describe "configuring the application" do it "should set solo mode to true" do @app.reconfigure Chef::Config[:solo].should be_true end describe "when in daemonized mode and no interval has been set" do before do Chef::Config[:daemonize] = true end it "should set the interval to 1800" do Chef::Config[:interval] = nil @app.reconfigure Chef::Config[:interval].should == 1800 end end describe "when the json_attribs configuration option is specified" do let(:json_attribs) { {"a" => "b"} } let(:config_fetcher) { double(Chef::ConfigFetcher, :fetch_json => json_attribs) } let(:json_source) { "https://foo.com/foo.json" } before do Chef::Config[:json_attribs] = json_source Chef::ConfigFetcher.should_receive(:new).with(json_source). and_return(config_fetcher) end it "reads the JSON attributes from the specified source" do @app.reconfigure @app.chef_client_json.should == json_attribs end end describe "when the recipe_url configuration option is specified" do before do Chef::Config[:cookbook_path] = "#{Dir.tmpdir}/chef-solo/cookbooks" Chef::Config[:recipe_url] = "http://junglist.gen.nz/recipes.tgz" FileUtils.stub!(:mkdir_p).and_return(true) @tarfile = StringIO.new("remote_tarball_content") @app.stub!(:open).with("http://junglist.gen.nz/recipes.tgz").and_yield(@tarfile) @target_file = StringIO.new File.stub!(:open).with("#{Dir.tmpdir}/chef-solo/recipes.tgz", "wb").and_yield(@target_file) Chef::Mixin::Command.stub!(:run_command).and_return(true) end it "should create the recipes path based on the parent of the cookbook path" do FileUtils.should_receive(:mkdir_p).with("#{Dir.tmpdir}/chef-solo").and_return(true) @app.reconfigure end it "should download the recipes" do @app.should_receive(:open).with("http://junglist.gen.nz/recipes.tgz").and_yield(@tarfile) @app.reconfigure end it "should write the recipes to the target path" do @app.reconfigure @target_file.string.should == "remote_tarball_content" end it "should untar the target file to the parent of the cookbook path" do Chef::Mixin::Command.should_receive(:run_command).with({:command => "tar zxvf #{Dir.tmpdir}/chef-solo/recipes.tgz -C #{Dir.tmpdir}/chef-solo"}).and_return(true) @app.reconfigure end end end describe "after the application has been configured" do before do Chef::Config[:solo] = true Chef::Daemon.stub!(:change_privilege) @chef_client = mock("Chef::Client") Chef::Client.stub!(:new).and_return(@chef_client) @app = Chef::Application::Solo.new # this is all stuff the reconfigure method needs @app.stub!(:configure_opt_parser).and_return(true) @app.stub!(:configure_chef).and_return(true) @app.stub!(:configure_logging).and_return(true) end it "should change privileges" do Chef::Daemon.should_receive(:change_privilege).and_return(true) @app.setup_application end end end chef-11.8.2/spec/unit/application/knife_spec.rb0000644000004100000410000001262212254362222021412 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'spec_helper' require "#{CHEF_SPEC_DATA}/knife_subcommand/test_yourself" describe Chef::Application::Knife do include SpecHelpers::Knife before(:all) do class NoopKnifeCommand < Chef::Knife option :opt_with_default, :short => "-D VALUE", :long => "-optwithdefault VALUE", :default => "default-value" def run end end end before(:each) do @knife = Chef::Application::Knife.new @knife.stub!(:puts) Chef::Knife.stub!(:list_commands) end it "should exit 1 and print the options if no arguments are given at all" do with_argv([]) do lambda { @knife.run }.should raise_error(SystemExit) { |e| e.status.should == 1 } end end it "should exit 2 if run without a sub command" do with_argv("--user", "adam") do Chef::Log.should_receive(:error).with(/you need to pass a sub\-command/i) lambda { @knife.run }.should raise_error(SystemExit) { |e| e.status.should == 2 } end end it "should run a sub command with the applications command line option prototype" do with_argv(*%w{noop knife command with some args}) do knife = mock(Chef::Knife) Chef::Knife.should_receive(:run).with(ARGV, @knife.options).and_return(knife) @knife.should_receive(:exit).with(0) @knife.run end end it "should set the colored output to false by default on windows and true otherwise" do with_argv(*%w{noop knife command}) do @knife.should_receive(:exit).with(0) @knife.run end if windows? Chef::Config[:color].should be_false else Chef::Config[:color].should be_true end end describe "when given a path to the client key" do it "expands a relative path relative to the CWD" do relative_path = '.chef/client.pem' Dir.stub!(:pwd).and_return(CHEF_SPEC_DATA) with_argv(*%W{noop knife command -k #{relative_path}}) do @knife.should_receive(:exit).with(0) @knife.run end Chef::Config[:client_key].should == File.join(CHEF_SPEC_DATA, relative_path) end it "expands a ~/home/path to the correct full path" do home_path = '~/.chef/client.pem' with_argv(*%W{noop knife command -k #{home_path}}) do @knife.should_receive(:exit).with(0) @knife.run end Chef::Config[:client_key].should == File.join(ENV['HOME'], '.chef/client.pem').gsub((File::ALT_SEPARATOR || '\\'), File::SEPARATOR) end it "does not expand a full path" do full_path = if windows? 'C:/chef/client.pem' else '/etc/chef/client.pem' end with_argv(*%W{noop knife command -k #{full_path}}) do @knife.should_receive(:exit).with(0) @knife.run end Chef::Config[:client_key].should == full_path end end describe "with environment configuration" do before do Chef::Config[:environment] = nil end it "should default to no environment" do with_argv(*%w{noop knife command}) do @knife.should_receive(:exit).with(0) @knife.run end Chef::Config[:environment].should == nil end it "should load the environment from the config file" do config_file = File.join(CHEF_SPEC_DATA,"environment-config.rb") with_argv(*%W{noop knife command -c #{config_file}}) do @knife.should_receive(:exit).with(0) @knife.run end Chef::Config[:environment].should == 'production' end it "should load the environment from the CLI options" do with_argv(*%W{noop knife command -E development}) do @knife.should_receive(:exit).with(0) @knife.run end Chef::Config[:environment].should == 'development' end it "should override the config file environment with the CLI environment" do config_file = File.join(CHEF_SPEC_DATA,"environment-config.rb") with_argv(*%W{noop knife command -c #{config_file} -E override}) do @knife.should_receive(:exit).with(0) @knife.run end Chef::Config[:environment].should == 'override' end it "should override the config file environment with the CLI environment regardless of order" do config_file = File.join(CHEF_SPEC_DATA,"environment-config.rb") with_argv(*%W{noop knife command -E override -c #{config_file}}) do @knife.should_receive(:exit).with(0) @knife.run end Chef::Config[:environment].should == 'override' end it "should run a sub command with the applications command line option prototype" do with_argv(*%w{noop knife command with some args}) do knife = mock(Chef::Knife) Chef::Knife.should_receive(:run).with(ARGV, @knife.options).and_return(knife) @knife.should_receive(:exit).with(0) @knife.run end end end end chef-11.8.2/spec/unit/application/client_spec.rb0000644000004100000410000000761512254362222021602 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'spec_helper' describe Chef::Application::Client, "reconfigure" do before do @original_argv = ARGV.dup ARGV.clear @app = Chef::Application::Client.new @app.stub!(:configure_opt_parser).and_return(true) @app.stub!(:configure_chef).and_return(true) @app.stub!(:configure_logging).and_return(true) Chef::Config[:interval] = 10 Chef::Config[:once] = false end after do ARGV.replace(@original_argv) end describe "when in daemonized mode and no interval has been set" do before do Chef::Config[:daemonize] = true Chef::Config[:interval] = nil end it "should set the interval to 1800" do @app.reconfigure Chef::Config.interval.should == 1800 end end describe "when configured to run once" do before do Chef::Config[:once] = true Chef::Config[:daemonize] = false Chef::Config[:splay] = 60 Chef::Config[:interval] = 1800 end it "ignores the splay" do @app.reconfigure Chef::Config.splay.should be_nil end it "forces the interval to nil" do @app.reconfigure Chef::Config.interval.should be_nil end end describe "when the json_attribs configuration option is specified" do let(:json_attribs) { {"a" => "b"} } let(:config_fetcher) { double(Chef::ConfigFetcher, :fetch_json => json_attribs) } let(:json_source) { "https://foo.com/foo.json" } before do Chef::Config[:json_attribs] = json_source Chef::ConfigFetcher.should_receive(:new).with(json_source). and_return(config_fetcher) end it "reads the JSON attributes from the specified source" do @app.reconfigure @app.chef_client_json.should == json_attribs end end end describe Chef::Application::Client, "setup_application" do before do @app = Chef::Application::Client.new # this is all stuff the reconfigure method needs @app.stub!(:configure_opt_parser).and_return(true) @app.stub!(:configure_chef).and_return(true) @app.stub!(:configure_logging).and_return(true) end it "should change privileges" do Chef::Daemon.should_receive(:change_privilege).and_return(true) @app.setup_application end after do Chef::Config[:solo] = false end end describe Chef::Application::Client, "configure_chef" do before do @original_argv = ARGV.dup ARGV.clear @app = Chef::Application::Client.new @app.configure_chef end after do ARGV.replace(@original_argv) end it "should set the colored output to false by default on windows and true otherwise" do if windows? Chef::Config[:color].should be_false else Chef::Config[:color].should be_true end end end describe Chef::Application::Client, "run_application", :unix_only do before do @pipe = IO.pipe @app = Chef::Application::Client.new @app.stub(:run_chef_client) do @pipe[1].puts 'started' sleep 1 @pipe[1].puts 'finished' end end it "should exit gracefully when sent SIGTERM" do pid = fork do @app.run_application end @pipe[0].gets.should == "started\n" Process.kill("TERM", pid) Process.wait IO.select([@pipe[0]], nil, nil, 0).should_not be_nil @pipe[0].gets.should == "finished\n" end end chef-11.8.2/spec/unit/application/apply.rb0000644000004100000410000000505412254362222020432 0ustar www-datawww-data# # Author:: Bryan W. Berry () # Copyright:: Copyright (c) 2012 Bryan W. Berry # License:: Apache License, Version 2.0 # # 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. require 'spec_helper' describe Chef::Application::Apply do before do @app = Chef::Application::Recipe.new @app.stub!(:configure_logging).and_return(true) @recipe_text = "package 'nyancat'" Chef::Config[:solo] = true end describe "configuring the application" do it "should set solo mode to true" do @app.reconfigure Chef::Config[:solo].should be_true end end describe "read_recipe_file" do before do @recipe_file_name = "foo.rb" @recipe_path = File.expand_path("foo.rb") @recipe_file = mock("Tempfile (mock)", :read => @recipe_text) @app.stub!(:open).with(@recipe_path).and_return(@recipe_file) File.stub!(:exist?).with("foo.rb").and_return(true) Chef::Application.stub!(:fatal!).and_return(true) end it "should read text properly" do @app.read_recipe_file(@recipe_file_name)[0].should == @recipe_text end it "should return a file_handle" do @app.read_recipe_file(@recipe_file_name)[1].should be_instance_of(RSpec::Mocks::Mock) end describe "when recipe doesn't exist" do before do File.stub!(:exist?).with(@recipe_file_name).and_return(false) end it "should raise a fatal" do Chef::Application.should_receive(:fatal!) @app.read_recipe_file(@recipe_file_name) end end end describe "temp_recipe_file" do before do @app.instance_variable_set(:@recipe_text, @recipe_text) @app.temp_recipe_file @recipe_fh = @app.instance_variable_get(:@recipe_fh) end it "should open a tempfile" do @recipe_fh.path.should match(/.*recipe-temporary-file.*/) end it "should write recipe text to the tempfile" do @recipe_fh.read.should == @recipe_text end it "should save the filename for later use" do @recipe_fh.path.should == @app.instance_variable_get(:@recipe_filename) end end end chef-11.8.2/spec/unit/application/agent_spec.rb0000644000004100000410000000000012254362222021377 0ustar www-datawww-datachef-11.8.2/spec/unit/windows_service_spec.rb0000644000004100000410000000424512254362222021227 0ustar www-datawww-data# # Author:: Mukta Aphale () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' if Chef::Platform.windows? require 'chef/application/windows_service' end describe "Chef::Application::WindowsService", :windows_only do let (:instance) {Chef::Application::WindowsService.new} let (:shell_out_result) {Object.new} let (:tempfile) {Tempfile.new "log_file"} before do instance.stub(:parse_options) shell_out_result.stub(:stdout) shell_out_result.stub(:stderr) end it "runs chef-client in new process" do instance.should_receive(:configure_chef).twice instance.service_init instance.should_receive(:run_chef_client).and_call_original instance.should_receive(:shell_out).and_return(shell_out_result) instance.stub(:running?).and_return(true, false) instance.instance_variable_get(:@service_signal).stub(:wait) instance.stub(:state).and_return(4) instance.service_main end it "passes config params to new process" do Chef::Config.merge!({:log_location => tempfile.path, :config_file => "test_config_file", :log_level => :info}) instance.should_receive(:configure_chef).twice instance.service_init instance.stub(:running?).and_return(true, false) instance.instance_variable_get(:@service_signal).stub(:wait) instance.stub(:state).and_return(4) instance.should_receive(:run_chef_client).and_call_original instance.should_receive(:shell_out).with("chef-client --no-fork -c test_config_file -L #{tempfile.path}").and_return(shell_out_result) instance.service_main tempfile.unlink end end chef-11.8.2/spec/unit/monkey_patches/0000755000004100000410000000000012254362222017462 5ustar www-datawww-datachef-11.8.2/spec/unit/monkey_patches/string_spec.rb0000644000004100000410000000211712254362222022330 0ustar www-datawww-data# # Author:: Devin Ben-Hur # Copyright:: Copyright (c) 2008, 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/monkey_patches/string' describe String do describe "#ord" do it "converts each ASCII-8BIT character to corresponding positive Fixnum" do (0..0xff).each do |num| ch = num.chr ch.force_encoding('ASCII-8BIT') if ch.respond_to? :force_encoding ch.ord.should be_a_kind_of(Fixnum) ch.ord.should == num end end end end chef-11.8.2/spec/unit/run_list_spec.rb0000644000004100000410000002402412254362222017651 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Seth Falcon () # Author:: Christopher Walters () # Copyright:: Copyright (c) 2008-2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/version_class' require 'chef/version_constraint' describe Chef::RunList do before(:each) do @run_list = Chef::RunList.new end describe "<<" do it "should add a recipe to the run list and recipe list with the fully qualified name" do @run_list << 'recipe[needy]' @run_list.should include('recipe[needy]') @run_list.recipes.should include("needy") end it "should add a role to the run list and role list with the fully qualified name" do @run_list << "role[woot]" @run_list.should include('role[woot]') @run_list.roles.should include('woot') end it "should accept recipes that are unqualified" do @run_list << "needy" @run_list.should include('recipe[needy]') @run_list.recipes.include?('needy').should == true end it "should not allow duplicates" do @run_list << "needy" @run_list << "needy" @run_list.run_list.length.should == 1 @run_list.recipes.length.should == 1 end it "should allow two versions of a recipe" do @run_list << "recipe[needy@0.2.0]" @run_list << "recipe[needy@0.1.0]" @run_list.run_list.length.should == 2 @run_list.recipes.length.should == 2 @run_list.recipes.include?('needy').should == true end it "should not allow duplicate versions of a recipe" do @run_list << "recipe[needy@0.2.0]" @run_list << "recipe[needy@0.2.0]" @run_list.run_list.length.should == 1 @run_list.recipes.length.should == 1 end end describe "add" do # Testing only the basic functionality here # since full behavior is tested above. it "should add a recipe to the run_list" do @run_list.add 'recipe[needy]' @run_list.should include('recipe[needy]') end it "should add a role to the run_list" do @run_list.add 'role[needy]' @run_list.should include('role[needy]') end end describe "==" do it "should believe two RunLists are equal if they have the same members" do @run_list << "foo" r = Chef::RunList.new r << "foo" @run_list.should == r end it "should believe a RunList is equal to an array named after it's members" do @run_list << "foo" @run_list << "baz" @run_list.should == [ "foo", "baz" ] end end describe "empty?" do it "should be emtpy if the run list has no members" do @run_list.empty?.should == true end it "should not be empty if the run list has members" do @run_list << "chromeo" @run_list.empty?.should == false end end describe "[]" do it "should let you look up a member in the run list by position" do @run_list << 'recipe[loulou]' @run_list[0].should == 'recipe[loulou]' end end describe "[]=" do it "should let you set a member of the run list by position" do @run_list[0] = 'recipe[loulou]' @run_list[0].should == 'recipe[loulou]' end it "should properly expand a member of the run list given by position" do @run_list[0] = 'loulou' @run_list[0].should == 'recipe[loulou]' end end describe "each" do it "should yield each member to your block" do @run_list << "foo" @run_list << "bar" seen = Array.new @run_list.each { |r| seen << r } seen.should be_include("recipe[foo]") seen.should be_include("recipe[bar]") end end describe "each_index" do it "should yield each members index to your block" do to_add = [ "recipe[foo]", "recipe[bar]", "recipe[baz]" ] to_add.each { |i| @run_list << i } @run_list.each_index { |i| @run_list[i].should == to_add[i] } end end describe "include?" do it "should be true if the run list includes the item" do @run_list << "foo" @run_list.include?("foo") end end describe "reset" do it "should reset the run_list based on the array you pass" do @run_list << "chromeo" list = %w{camp chairs snakes clowns} @run_list.reset!(list) list.each { |i| @run_list.should be_include(i) } @run_list.include?("chromeo").should == false end end describe "when expanding the run list" do before(:each) do @role = Chef::Role.new @role.name "stubby" @role.run_list "one", "two" @role.default_attributes :one => :two @role.override_attributes :three => :four Chef::Role.stub!(:load).and_return(@role) @rest = mock("Chef::REST", { :get_rest => @role, :url => "/" }) Chef::REST.stub!(:new).and_return(@rest) @run_list << "role[stubby]" @run_list << "kitty" end describe "from disk" do it "should load the role from disk" do Chef::Role.should_receive(:from_disk).with("stubby") @run_list.expand("_default", "disk") end it "should log a helpful error if the role is not available" do Chef::Role.stub!(:from_disk).and_raise(Chef::Exceptions::RoleNotFound) Chef::Log.should_receive(:error).with("Role stubby (included by 'top level') is in the runlist but does not exist. Skipping expand.") @run_list.expand("_default", "disk") end end describe "from the chef server" do it "should load the role from the chef server" do #@rest.should_receive(:get_rest).with("roles/stubby") expansion = @run_list.expand("_default", "server") expansion.recipes.should == ['one', 'two', 'kitty'] end it "should default to expanding from the server" do @rest.should_receive(:get_rest).with("roles/stubby") @run_list.expand("_default") end describe "with an environment set" do before do @role.env_run_list["production"] = Chef::RunList.new( "one", "two", "five") end it "expands the run list using the environment specific run list" do expansion = @run_list.expand("production", "server") expansion.recipes.should == %w{one two five kitty} end describe "and multiply nested roles" do before do @multiple_rest_requests = mock("Chef::REST") @role.env_run_list["production"] << "role[prod-base]" @role_prod_base = Chef::Role.new @role_prod_base.name("prod-base") @role_prod_base.env_run_list["production"] = Chef::RunList.new("role[nested-deeper]") @role_nested_deeper = Chef::Role.new @role_nested_deeper.name("nested-deeper") @role_nested_deeper.env_run_list["production"] = Chef::RunList.new("recipe[prod-secret-sauce]") end it "expands the run list using the specified environment for all nested roles" do Chef::REST.stub!(:new).and_return(@multiple_rest_requests) @multiple_rest_requests.should_receive(:get_rest).with("roles/stubby").and_return(@role) @multiple_rest_requests.should_receive(:get_rest).with("roles/prod-base").and_return(@role_prod_base) @multiple_rest_requests.should_receive(:get_rest).with("roles/nested-deeper").and_return(@role_nested_deeper) expansion = @run_list.expand("production", "server") expansion.recipes.should == %w{one two five prod-secret-sauce kitty} end end end end it "should return the list of expanded recipes" do expansion = @run_list.expand("_default") expansion.recipes[0].should == "one" expansion.recipes[1].should == "two" end it "should return the list of default attributes" do expansion = @run_list.expand("_default") expansion.default_attrs[:one].should == :two end it "should return the list of override attributes" do expansion = @run_list.expand("_default") expansion.override_attrs[:three].should == :four end it "should recurse into a child role" do dog = Chef::Role.new dog.name "dog" dog.default_attributes :seven => :nine dog.run_list "three" @role.run_list << "role[dog]" Chef::Role.stub!(:from_disk).with("stubby").and_return(@role) Chef::Role.stub!(:from_disk).with("dog").and_return(dog) expansion = @run_list.expand("_default", 'disk') expansion.recipes[2].should == "three" expansion.default_attrs[:seven].should == :nine end it "should not recurse infinitely" do dog = Chef::Role.new dog.name "dog" dog.default_attributes :seven => :nine dog.run_list "role[dog]", "three" @role.run_list << "role[dog]" Chef::Role.stub!(:from_disk).with("stubby").and_return(@role) Chef::Role.should_receive(:from_disk).with("dog").once.and_return(dog) expansion = @run_list.expand("_default", 'disk') expansion.recipes[2].should == "three" expansion.recipes[3].should == "kitty" expansion.default_attrs[:seven].should == :nine end end describe "when converting to an alternate representation" do before do @run_list << "recipe[nagios::client]" << "role[production]" << "recipe[apache2]" end it "converts to an array of the string forms of its items" do @run_list.to_a.should == ["recipe[nagios::client]", "role[production]", "recipe[apache2]"] end it "converts to json by converting its array form" do @run_list.to_json.should == ["recipe[nagios::client]", "role[production]", "recipe[apache2]"].to_json end end end chef-11.8.2/spec/unit/mash_spec.rb0000644000004100000410000000306212254362222016741 0ustar www-datawww-data# # Author:: Matthew Kent () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/mash' describe Mash do it "should duplicate a simple key/value mash to a new mash" do data = {:x=>"one", :y=>"two", :z=>"three"} @orig = Mash.new(data) @copy = @orig.dup @copy.to_hash.should == Mash.new(data).to_hash @copy[:x] = "four" @orig[:x].should == "one" end it "should duplicate a mash with an array to a new mash" do data = {:x=>"one", :y=>"two", :z=>[1,2,3]} @orig = Mash.new(data) @copy = @orig.dup @copy.to_hash.should == Mash.new(data).to_hash @copy[:z] << 4 @orig[:z].should == [1,2,3] end it "should duplicate a nested mash to a new mash" do data = {:x=>"one", :y=>"two", :z=>Mash.new({:a=>[1,2,3]})} @orig = Mash.new(data) @copy = @orig.dup @copy.to_hash.should == Mash.new(data).to_hash @copy[:z][:a] << 4 @orig[:z][:a].should == [1,2,3] end # add more! end chef-11.8.2/spec/unit/lwrp_spec.rb0000644000004100000410000002726112254362222017004 0ustar www-datawww-data# # Author:: Christopher Walters () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' module LwrpConstScopingConflict end describe "LWRP" do before do @original_VERBOSE = $VERBOSE $VERBOSE = nil end after do $VERBOSE = @original_VERBOSE end describe "when overriding an existing class" do before :each do $stderr.stub!(:write) end it "should log if attempting to load resource of same name" do Dir[File.expand_path( "lwrp/resources/*", CHEF_SPEC_DATA)].each do |file| Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil) end Dir[File.expand_path( "lwrp/resources/*", CHEF_SPEC_DATA)].each do |file| Chef::Log.should_receive(:info).with(/overriding/) Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil) end end it "should log if attempting to load provider of same name" do Dir[File.expand_path( "lwrp/providers/*", CHEF_SPEC_DATA)].each do |file| Chef::Provider::LWRPBase.build_from_file("lwrp", file, nil) end Dir[File.expand_path( "lwrp/providers/*", CHEF_SPEC_DATA)].each do |file| Chef::Log.should_receive(:info).with(/overriding/) Chef::Provider::LWRPBase.build_from_file("lwrp", file, nil) end end it "removes the old LRWP resource class from the list of resource subclasses [CHEF-3432]" do # CHEF-3432 regression test: # Chef::Resource keeps a list of all subclasses to assist class inflation # for json parsing (see Chef::JSONCompat). When replacing LWRP resources, # we need to ensure the old resource class is remove from that list. Dir[File.expand_path( "lwrp/resources/*", CHEF_SPEC_DATA)].each do |file| Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil) end first_lwr_foo_class = Chef::Resource::LwrpFoo Chef::Resource.resource_classes.should include(first_lwr_foo_class) Dir[File.expand_path( "lwrp/resources/*", CHEF_SPEC_DATA)].each do |file| Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil) end Chef::Resource.resource_classes.should_not include(first_lwr_foo_class) end it "does not attempt to remove classes from higher up namespaces [CHEF-4117]" do conflicting_lwrp_file = File.expand_path( "lwrp_const_scoping/resources/conflict.rb", CHEF_SPEC_DATA) # The test is that this should not raise an error: Chef::Resource::LWRPBase.build_from_file("lwrp_const_scoping", conflicting_lwrp_file, nil) end end describe "Lightweight Chef::Resource" do before do Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp", "resources", "*"))].each do |file| Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil) end Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp_override", "resources", "*"))].each do |file| Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil) end end it "should load the resource into a properly-named class" do Chef::Resource.const_get("LwrpFoo").should be_kind_of(Class) end it "should set resource_name" do Chef::Resource::LwrpFoo.new("blah").resource_name.should eql(:lwrp_foo) end it "should add the specified actions to the allowed_actions array" do Chef::Resource::LwrpFoo.new("blah").allowed_actions.should include(:pass_buck, :twiddle_thumbs) end it "should set the specified action as the default action" do Chef::Resource::LwrpFoo.new("blah").action.should == :pass_buck end it "should create a method for each attribute" do Chef::Resource::LwrpFoo.new("blah").methods.map{ |m| m.to_sym}.should include(:monkey) end it "should build attribute methods that respect validation rules" do lambda { Chef::Resource::LwrpFoo.new("blah").monkey(42) }.should raise_error(ArgumentError) end it "should have access to the run context and node during class definition" do node = Chef::Node.new node.normal[:penguin_name] = "jackass" run_context = Chef::RunContext.new(node, Chef::CookbookCollection.new, @events) Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp", "resources_with_default_attributes", "*"))].each do |file| Chef::Resource::LWRPBase.build_from_file("lwrp", file, run_context) end cls = Chef::Resource.const_get("LwrpNodeattr") cls.node.should be_kind_of(Chef::Node) cls.run_context.should be_kind_of(Chef::RunContext) cls.node[:penguin_name].should eql("jackass") end end describe "Lightweight Chef::Provider" do before do @node = Chef::Node.new @node.automatic[:platform] = :ubuntu @node.automatic[:platform_version] = '8.10' @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, Chef::CookbookCollection.new({}), @events) @runner = Chef::Runner.new(@run_context) end before(:each) do Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp", "resources", "*"))].each do |file| Chef::Resource::LWRPBase.build_from_file("lwrp", file, @run_context) end Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp_override", "resources", "*"))].each do |file| Chef::Resource::LWRPBase.build_from_file("lwrp", file, @run_context) end Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp", "providers", "*"))].each do |file| Chef::Provider::LWRPBase.build_from_file("lwrp", file, @run_context) end Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp_override", "providers", "*"))].each do |file| Chef::Provider::LWRPBase.build_from_file("lwrp", file, @run_context) end end it "should properly handle a new_resource reference" do resource = Chef::Resource::LwrpFoo.new("morpheus") resource.monkey("bob") resource.provider(:lwrp_monkey_name_printer) resource.run_context = @run_context provider = Chef::Platform.provider_for_resource(resource, :twiddle_thumbs) provider.action_twiddle_thumbs end it "should load the provider into a properly-named class" do Chef::Provider.const_get("LwrpBuckPasser").should be_kind_of(Class) end it "should create a method for each attribute" do new_resource = mock("new resource", :null_object=>true) Chef::Provider::LwrpBuckPasser.new(nil, new_resource).methods.map{|m|m.to_sym}.should include(:action_pass_buck) Chef::Provider::LwrpThumbTwiddler.new(nil, new_resource).methods.map{|m|m.to_sym}.should include(:action_twiddle_thumbs) end it "should insert resources embedded in the provider into the middle of the resource collection" do injector = Chef::Resource::LwrpFoo.new("morpheus", @run_context) injector.action(:pass_buck) injector.provider(:lwrp_buck_passer) dummy = Chef::Resource::ZenMaster.new("keanu reeves", @run_context) dummy.provider(Chef::Provider::Easy) @run_context.resource_collection.insert(injector) @run_context.resource_collection.insert(dummy) Chef::Runner.new(@run_context).converge @run_context.resource_collection[0].should eql(injector) @run_context.resource_collection[1].name.should eql(:prepared_thumbs) @run_context.resource_collection[2].name.should eql(:twiddled_thumbs) @run_context.resource_collection[3].should eql(dummy) end it "should insert embedded resources from multiple providers, including from the last position, properly into the resource collection" do injector = Chef::Resource::LwrpFoo.new("morpheus", @run_context) injector.action(:pass_buck) injector.provider(:lwrp_buck_passer) injector2 = Chef::Resource::LwrpBar.new("tank", @run_context) injector2.action(:pass_buck) injector2.provider(:lwrp_buck_passer_2) dummy = Chef::Resource::ZenMaster.new("keanu reeves", @run_context) dummy.provider(Chef::Provider::Easy) @run_context.resource_collection.insert(injector) @run_context.resource_collection.insert(dummy) @run_context.resource_collection.insert(injector2) Chef::Runner.new(@run_context).converge @run_context.resource_collection[0].should eql(injector) @run_context.resource_collection[1].name.should eql(:prepared_thumbs) @run_context.resource_collection[2].name.should eql(:twiddled_thumbs) @run_context.resource_collection[3].should eql(dummy) @run_context.resource_collection[4].should eql(injector2) @run_context.resource_collection[5].name.should eql(:prepared_eyes) @run_context.resource_collection[6].name.should eql(:dried_paint_watched) end it "should properly handle a new_resource reference" do resource = Chef::Resource::LwrpFoo.new("morpheus", @run_context) resource.monkey("bob") resource.provider(:lwrp_monkey_name_printer) provider = Chef::Platform.provider_for_resource(resource, :twiddle_thumbs) provider.action_twiddle_thumbs provider.monkey_name.should == "my monkey's name is 'bob'" end it "should properly handle an embedded Resource accessing the enclosing Provider's scope" do resource = Chef::Resource::LwrpFoo.new("morpheus", @run_context) resource.monkey("bob") resource.provider(:lwrp_embedded_resource_accesses_providers_scope) provider = Chef::Platform.provider_for_resource(resource, :twiddle_thumbs) #provider = @runner.build_provider(resource) provider.action_twiddle_thumbs provider.enclosed_resource.monkey.should == 'bob, the monkey' end describe "when using inline compilation" do before do # Behavior in these examples depends on implementation of fixture provider. # See spec/data/lwrp/providers/inline_compiler # Side effect of lwrp_inline_compiler provider for testing notifications. $interior_ruby_block_2 = nil # resource type doesn't matter, so make an existing resource type work with provider. @resource = Chef::Resource::LwrpFoo.new("morpheus", @run_context) @resource.allowed_actions << :test @resource.action(:test) @resource.provider(:lwrp_inline_compiler) end it "does not add interior resources to the exterior resource collection" do @resource.run_action(:test) @run_context.resource_collection.should be_empty end context "when interior resources are updated" do it "processes notifications within the LWRP provider's action" do @resource.run_action(:test) $interior_ruby_block_2.should == "executed" end it "marks the parent resource updated" do @resource.run_action(:test) @resource.should be_updated @resource.should be_updated_by_last_action end end context "when interior resources are not updated" do it "does not mark the parent resource updated" do @resource.run_action(:no_updates) @resource.should_not be_updated @resource.should_not be_updated_by_last_action end end end end end chef-11.8.2/spec/unit/knife_spec.rb0000644000004100000410000003702012254362222017106 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tim Hinderliter () # Copyright:: Copyright (c) 2008, 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # # Fixtures for subcommand loading live in this namespace module KnifeSpecs end require 'spec_helper' describe Chef::Knife do before(:each) do Chef::Log.logger = Logger.new(StringIO.new) Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife.new @knife.ui.stub!(:puts) @knife.ui.stub!(:print) Chef::Log.stub!(:init) Chef::Log.stub!(:level) [:debug, :info, :warn, :error, :crit].each do |level_sym| Chef::Log.stub!(level_sym) end Chef::Knife.stub!(:puts) @stdout = StringIO.new end describe "selecting a config file" do context "when the current working dir is inside a symlinked directory" do before do Chef::Knife.reset_config_path! # pwd according to your shell is /home/someuser/prod/chef-repo, but # chef-repo is a symlink to /home/someuser/codes/chef-repo ENV.stub!(:[]).with("PWD").and_return("/home/someuser/prod/chef-repo") Dir.stub!(:pwd).and_return("/home/someuser/codes/chef-repo") end after do Chef::Knife.reset_config_path! end it "loads the config from the non-dereferenced directory path" do File.should_receive(:exist?).with("/home/someuser/prod/chef-repo/.chef").and_return(false) File.should_receive(:exist?).with("/home/someuser/prod/.chef").and_return(true) File.should_receive(:directory?).with("/home/someuser/prod/.chef").and_return(true) Chef::Knife.chef_config_dir.should == "/home/someuser/prod/.chef" end end end describe "after loading a subcommand" do before do Chef::Knife.reset_subcommands! if KnifeSpecs.const_defined?(:TestNameMapping) KnifeSpecs.send(:remove_const, :TestNameMapping) end if KnifeSpecs.const_defined?(:TestExplicitCategory) KnifeSpecs.send(:remove_const, :TestExplicitCategory) end Kernel.load(File.join(CHEF_SPEC_DATA, 'knife_subcommand', 'test_name_mapping.rb')) Kernel.load(File.join(CHEF_SPEC_DATA, 'knife_subcommand', 'test_explicit_category.rb')) end it "has a category based on its name" do KnifeSpecs::TestNameMapping.subcommand_category.should == 'test' end it "has an explictly defined category if set" do KnifeSpecs::TestExplicitCategory.subcommand_category.should == 'cookbook site' end it "can reference the subcommand by its snake cased name" do Chef::Knife.subcommands['test_name_mapping'].should equal(KnifeSpecs::TestNameMapping) end it "lists subcommands by category" do Chef::Knife.subcommands_by_category['test'].should include('test_name_mapping') end it "lists subcommands by category when the subcommands have explicit categories" do Chef::Knife.subcommands_by_category['cookbook site'].should include('test_explicit_category') end it "has empty dependency_loader list by default" do KnifeSpecs::TestNameMapping.dependency_loaders.should be_empty end end describe "after loading all subcommands" do before do Chef::Knife.reset_subcommands! Chef::Knife.load_commands end it "references a subcommand class by its snake cased name" do class SuperAwesomeCommand < Chef::Knife end Chef::Knife.load_commands Chef::Knife.subcommands.should have_key("super_awesome_command") Chef::Knife.subcommands["super_awesome_command"].should == SuperAwesomeCommand end it "guesses a category from a given ARGV" do Chef::Knife.subcommands_by_category["cookbook"] << :cookbook Chef::Knife.subcommands_by_category["cookbook site"] << :cookbook_site Chef::Knife.guess_category(%w{cookbook foo bar baz}).should == 'cookbook' Chef::Knife.guess_category(%w{cookbook site foo bar baz}).should == 'cookbook site' Chef::Knife.guess_category(%w{cookbook site --help}).should == 'cookbook site' end it "finds a subcommand class based on ARGV" do Chef::Knife.subcommands["cookbook_site_vendor"] = :CookbookSiteVendor Chef::Knife.subcommands["cookbook"] = :Cookbook Chef::Knife.subcommand_class_from(%w{cookbook site vendor --help foo bar baz}).should == :CookbookSiteVendor end end describe "when running a command" do before(:each) do if KnifeSpecs.const_defined?(:TestYourself) KnifeSpecs.send :remove_const, :TestYourself end Kernel.load(File.join(CHEF_SPEC_DATA, 'knife_subcommand', 'test_yourself.rb')) Chef::Knife.subcommands.each { |name, klass| Chef::Knife.subcommands.delete(name) unless klass.kind_of?(Class) } end it "merges the global knife CLI options" do extra_opts = {} extra_opts[:editor] = {:long=>"--editor EDITOR", :description=>"Set the editor to use for interactive commands", :short=>"-e EDITOR", :default=>"/usr/bin/vim"} # there is special hackery to return the subcommand instance going on here. command = Chef::Knife.run(%w{test yourself}, extra_opts) editor_opts = command.options[:editor] editor_opts[:long].should == "--editor EDITOR" editor_opts[:description].should == "Set the editor to use for interactive commands" editor_opts[:short].should == "-e EDITOR" editor_opts[:default].should == "/usr/bin/vim" end it "creates an instance of the subcommand and runs it" do command = Chef::Knife.run(%w{test yourself}) command.should be_an_instance_of(KnifeSpecs::TestYourself) command.ran.should be_true end it "passes the command specific args to the subcommand" do command = Chef::Knife.run(%w{test yourself with some args}) command.name_args.should == %w{with some args} end it "excludes the command name from the name args when parts are joined with underscores" do command = Chef::Knife.run(%w{test_yourself with some args}) command.name_args.should == %w{with some args} end it "exits if no subcommand matches the CLI args" do Chef::Knife.ui.stub!(:stdout).and_return(@stdout) Chef::Knife.ui.should_receive(:fatal) lambda {Chef::Knife.run(%w{fuuu uuuu fuuuu})}.should raise_error(SystemExit) { |e| e.status.should_not == 0 } end it "loads lazy dependencies" do command = Chef::Knife.run(%w{test yourself}) KnifeSpecs::TestYourself.test_deps_loaded.should be_true end it "loads lazy dependencies from multiple deps calls" do other_deps_loaded = false KnifeSpecs::TestYourself.class_eval do deps { other_deps_loaded = true } end command = Chef::Knife.run(%w{test yourself}) KnifeSpecs::TestYourself.test_deps_loaded.should be_true other_deps_loaded.should be_true end describe "merging configuration options" do before do KnifeSpecs::TestYourself.option(:opt_with_default, :short => "-D VALUE", :default => "default-value") end it "prefers the default value if no config or command line value is present" do knife_command = KnifeSpecs::TestYourself.new([]) #empty argv knife_command.configure_chef knife_command.config[:opt_with_default].should == "default-value" end it "prefers a value in Chef::Config[:knife] to the default" do Chef::Config[:knife][:opt_with_default] = "from-knife-config" knife_command = KnifeSpecs::TestYourself.new([]) #empty argv knife_command.configure_chef knife_command.config[:opt_with_default].should == "from-knife-config" end it "prefers a value from command line over Chef::Config and the default" do Chef::Config[:knife][:opt_with_default] = "from-knife-config" knife_command = KnifeSpecs::TestYourself.new(["-D", "from-cli"]) knife_command.configure_chef knife_command.config[:opt_with_default].should == "from-cli" end end end describe "when first created" do before do unless KnifeSpecs.const_defined?(:TestYourself) Kernel.load(File.join(CHEF_SPEC_DATA, 'knife_subcommand', 'test_yourself.rb')) end @knife = KnifeSpecs::TestYourself.new(%w{with some args -s scrogramming}) end it "it parses the options passed to it" do @knife.config[:scro].should == 'scrogramming' end it "extracts its command specific args from the full arg list" do @knife.name_args.should == %w{with some args} end it "does not have lazy dependencies loaded" do @knife.class.test_deps_loaded.should_not be_true end end describe "when formatting exceptions" do before do @stdout, @stderr, @stdin = StringIO.new, StringIO.new, StringIO.new @knife.ui = Chef::Knife::UI.new(@stdout, @stderr, @stdin, {}) @knife.should_receive(:exit).with(100) end it "formats 401s nicely" do response = Net::HTTPUnauthorized.new("1.1", "401", "Unauthorized") response.instance_variable_set(:@read, true) # I hate you, net/http. response.stub!(:body).and_return(Chef::JSONCompat.to_json(:error => "y u no syncronize your clock?")) @knife.stub!(:run).and_raise(Net::HTTPServerException.new("401 Unauthorized", response)) @knife.run_with_pretty_exceptions @stderr.string.should match(/ERROR: Failed to authenticate to/) @stdout.string.should match(/Response: y u no syncronize your clock\?/) end it "formats 403s nicely" do response = Net::HTTPForbidden.new("1.1", "403", "Forbidden") response.instance_variable_set(:@read, true) # I hate you, net/http. response.stub!(:body).and_return(Chef::JSONCompat.to_json(:error => "y u no administrator")) @knife.stub!(:run).and_raise(Net::HTTPServerException.new("403 Forbidden", response)) @knife.stub!(:username).and_return("sadpanda") @knife.run_with_pretty_exceptions @stderr.string.should match(%r[ERROR: You authenticated successfully to http.+ as sadpanda but you are not authorized for this action]) @stdout.string.should match(%r[Response: y u no administrator]) end it "formats 400s nicely" do response = Net::HTTPBadRequest.new("1.1", "400", "Bad Request") response.instance_variable_set(:@read, true) # I hate you, net/http. response.stub!(:body).and_return(Chef::JSONCompat.to_json(:error => "y u search wrong")) @knife.stub!(:run).and_raise(Net::HTTPServerException.new("400 Bad Request", response)) @knife.run_with_pretty_exceptions @stderr.string.should match(%r[ERROR: The data in your request was invalid]) @stdout.string.should match(%r[Response: y u search wrong]) end it "formats 404s nicely" do response = Net::HTTPNotFound.new("1.1", "404", "Not Found") response.instance_variable_set(:@read, true) # I hate you, net/http. response.stub!(:body).and_return(Chef::JSONCompat.to_json(:error => "nothing to see here")) @knife.stub!(:run).and_raise(Net::HTTPServerException.new("404 Not Found", response)) @knife.run_with_pretty_exceptions @stderr.string.should match(%r[ERROR: The object you are looking for could not be found]) @stdout.string.should match(%r[Response: nothing to see here]) end it "formats 500s nicely" do response = Net::HTTPInternalServerError.new("1.1", "500", "Internal Server Error") response.instance_variable_set(:@read, true) # I hate you, net/http. response.stub!(:body).and_return(Chef::JSONCompat.to_json(:error => "sad trombone")) @knife.stub!(:run).and_raise(Net::HTTPFatalError.new("500 Internal Server Error", response)) @knife.run_with_pretty_exceptions @stderr.string.should match(%r[ERROR: internal server error]) @stdout.string.should match(%r[Response: sad trombone]) end it "formats 502s nicely" do response = Net::HTTPBadGateway.new("1.1", "502", "Bad Gateway") response.instance_variable_set(:@read, true) # I hate you, net/http. response.stub!(:body).and_return(Chef::JSONCompat.to_json(:error => "sadder trombone")) @knife.stub!(:run).and_raise(Net::HTTPFatalError.new("502 Bad Gateway", response)) @knife.run_with_pretty_exceptions @stderr.string.should match(%r[ERROR: bad gateway]) @stdout.string.should match(%r[Response: sadder trombone]) end it "formats 503s nicely" do response = Net::HTTPServiceUnavailable.new("1.1", "503", "Service Unavailable") response.instance_variable_set(:@read, true) # I hate you, net/http. response.stub!(:body).and_return(Chef::JSONCompat.to_json(:error => "saddest trombone")) @knife.stub!(:run).and_raise(Net::HTTPFatalError.new("503 Service Unavailable", response)) @knife.run_with_pretty_exceptions @stderr.string.should match(%r[ERROR: Service temporarily unavailable]) @stdout.string.should match(%r[Response: saddest trombone]) end it "formats other HTTP errors nicely" do response = Net::HTTPPaymentRequired.new("1.1", "402", "Payment Required") response.instance_variable_set(:@read, true) # I hate you, net/http. response.stub!(:body).and_return(Chef::JSONCompat.to_json(:error => "nobugfixtillyoubuy")) @knife.stub!(:run).and_raise(Net::HTTPServerException.new("402 Payment Required", response)) @knife.run_with_pretty_exceptions @stderr.string.should match(%r[ERROR: Payment Required]) @stdout.string.should match(%r[Response: nobugfixtillyoubuy]) end it "formats NameError and NoMethodError nicely" do @knife.stub!(:run).and_raise(NameError.new("Undefined constant FUUU")) @knife.run_with_pretty_exceptions @stderr.string.should match(%r[ERROR: knife encountered an unexpected error]) @stdout.string.should match(%r[This may be a bug in the 'knife' knife command or plugin]) @stdout.string.should match(%r[Exception: NameError: Undefined constant FUUU]) end it "formats missing private key errors nicely" do @knife.stub!(:run).and_raise(Chef::Exceptions::PrivateKeyMissing.new('key not there')) @knife.stub!(:api_key).and_return("/home/root/.chef/no-key-here.pem") @knife.run_with_pretty_exceptions @stderr.string.should match(%r[ERROR: Your private key could not be loaded from /home/root/.chef/no-key-here.pem]) @stdout.string.should match(%r[Check your configuration file and ensure that your private key is readable]) end it "formats connection refused errors nicely" do @knife.stub!(:run).and_raise(Errno::ECONNREFUSED.new('y u no shut up')) @knife.run_with_pretty_exceptions # Errno::ECONNREFUSED message differs by platform # *nix = Errno::ECONNREFUSED: Connection refused # win32: Errno::ECONNREFUSED: No connection could be made because the target machine actively refused it. @stderr.string.should match(%r[ERROR: Network Error: .* - y u no shut up]) @stdout.string.should match(%r[Check your knife configuration and network settings]) end end end chef-11.8.2/spec/unit/chef_spec.rb0000644000004100000410000000147112254362222016720 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef do it "should have a version defined" do Chef::VERSION.should match(/(\d+)\.(\d+)\.(\d+)/) end end chef-11.8.2/spec/unit/cookbook/0000755000004100000410000000000012254362222016257 5ustar www-datawww-datachef-11.8.2/spec/unit/cookbook/synchronizer_spec.rb0000644000004100000410000003134412254362222022360 0ustar www-datawww-datarequire 'spec_helper' require 'chef/cookbook/synchronizer' require 'chef/cookbook_version' describe Chef::CookbookCacheCleaner do describe "when cleaning up unused cookbook components" do before do @cleaner = Chef::CookbookCacheCleaner.instance @cleaner.reset! end it "removes all files that belong to unused cookbooks" do end it "removes all files not validated during the chef run" do file_cache = mock("Chef::FileCache with files from unused cookbooks") unused_template_files = %w{cookbooks/unused/templates/default/foo.conf.erb cookbooks/unused/tempaltes/default/bar.conf.erb} valid_cached_cb_files = %w{cookbooks/valid1/recipes/default.rb cookbooks/valid2/recipes/default.rb} @cleaner.mark_file_as_valid('cookbooks/valid1/recipes/default.rb') @cleaner.mark_file_as_valid('cookbooks/valid2/recipes/default.rb') file_cache.should_receive(:find).with(File.join(%w{cookbooks ** *})).and_return(valid_cached_cb_files + unused_template_files) file_cache.should_receive(:delete).with('cookbooks/unused/templates/default/foo.conf.erb') file_cache.should_receive(:delete).with('cookbooks/unused/tempaltes/default/bar.conf.erb') cookbook_hash = {"valid1"=> {}, "valid2" => {}} @cleaner.stub!(:cache).and_return(file_cache) @cleaner.cleanup_file_cache end describe "on chef-solo" do before do Chef::Config[:solo] = true end after do Chef::Config[:solo] = false end it "does not remove anything" do @cleaner.cache.stub!(:find).and_return(%w{cookbooks/valid1/recipes/default.rb cookbooks/valid2/recipes/default.rb}) @cleaner.cache.should_not_receive(:delete) @cleaner.cleanup_file_cache end end end end describe Chef::CookbookSynchronizer do before do segments = [ :resources, :providers, :recipes, :definitions, :libraries, :attributes, :files, :templates, :root_files ] @cookbook_manifest = {} @cookbook_a = Chef::CookbookVersion.new("cookbook_a") @cookbook_a_manifest = segments.inject({}) {|h, segment| h[segment.to_s] = []; h} @cookbook_a_default_recipe = { "path" => "recipes/default.rb", "url" => "http://chef.example.com/abc123", "checksum" => "abc123" } @cookbook_a_manifest["recipes"] = [ @cookbook_a_default_recipe ] @cookbook_a_default_attrs = { "path" => "attributes/default.rb", "url" => "http://chef.example.com/abc456", "checksum" => "abc456" } @cookbook_a_manifest["attributes"] = [ @cookbook_a_default_attrs ] @cookbook_a_manifest["templates"] = [{"path" => "templates/default/apache2.conf.erb", "url" => "http://chef.example.com/ffffff"}] @cookbook_a_manifest["files"] = [{"path" => "files/default/megaman.conf", "url" => "http://chef.example.com/megaman.conf"}] @cookbook_a.manifest = @cookbook_a_manifest @cookbook_manifest["cookbook_a"] = @cookbook_a @events = Chef::EventDispatch::Dispatcher.new @synchronizer = Chef::CookbookSynchronizer.new(@cookbook_manifest, @events) end it "lists the cookbook names" do @synchronizer.cookbook_names.should == %w[cookbook_a] end it "lists the cookbook manifests" do @synchronizer.cookbooks.should == [@cookbook_a] end context "when the cache contains unneeded cookbooks" do before do @file_cache = mock("Chef::FileCache with files from unused cookbooks") @valid_cached_cb_files = %w{cookbooks/valid1/recipes/default.rb cookbooks/valid2/recipes/default.rb} @obsolete_cb_files = %w{cookbooks/old1/recipes/default.rb cookbooks/old2/recipes/default.rb} @cookbook_hash = {"valid1"=> {}, "valid2" => {}} @synchronizer = Chef::CookbookSynchronizer.new(@cookbook_hash, @events) end it "removes unneeded cookbooks" do @file_cache.should_receive(:find).with(File.join(%w{cookbooks ** *})).and_return(@valid_cached_cb_files + @obsolete_cb_files) @file_cache.should_receive(:delete).with('cookbooks/old1/recipes/default.rb') @file_cache.should_receive(:delete).with('cookbooks/old2/recipes/default.rb') @synchronizer.stub!(:cache).and_return(@file_cache) @synchronizer.clear_obsoleted_cookbooks end end describe "when syncing cookbooks with the server" do before do # Would rather not stub out methods on the test subject, but setting up # the state is a PITA and tests for this behavior are above. @synchronizer.stub!(:clear_obsoleted_cookbooks) @server_api = mock("Chef::REST (mock)") @file_cache = mock("Chef::FileCache (mock)") @synchronizer.stub!(:server_api).and_return(@server_api) @synchronizer.stub!(:cache).and_return(@file_cache) @cookbook_a_default_recipe_tempfile = mock("Tempfile for cookbook_a default.rb recipe", :path => "/tmp/cookbook_a_recipes_default_rb") @cookbook_a_default_attribute_tempfile = mock("Tempfile for cookbook_a default.rb attr file", :path => "/tmp/cookbook_a_attributes_default_rb") end context "when the cache does not contain the desired files" do before do # Files are not in the cache: @file_cache.should_receive(:has_key?). with("cookbooks/cookbook_a/recipes/default.rb"). and_return(false) @file_cache.should_receive(:has_key?). with("cookbooks/cookbook_a/attributes/default.rb"). and_return(false) # Fetch and copy default.rb recipe @server_api.should_receive(:get_rest). with('http://chef.example.com/abc123', true). and_return(@cookbook_a_default_recipe_tempfile) @file_cache.should_receive(:move_to). with("/tmp/cookbook_a_recipes_default_rb", "cookbooks/cookbook_a/recipes/default.rb") @file_cache.should_receive(:load). with("cookbooks/cookbook_a/recipes/default.rb", false). and_return("/file-cache/cookbooks/cookbook_a/recipes/default.rb") # Fetch and copy default.rb attribute file @server_api.should_receive(:get_rest). with('http://chef.example.com/abc456', true). and_return(@cookbook_a_default_attribute_tempfile) @file_cache.should_receive(:move_to). with("/tmp/cookbook_a_attributes_default_rb", "cookbooks/cookbook_a/attributes/default.rb") @file_cache.should_receive(:load). with("cookbooks/cookbook_a/attributes/default.rb", false). and_return("/file-cache/cookbooks/cookbook_a/attributes/default.rb") end it "fetches eagerly loaded files" do @synchronizer.sync_cookbooks end it "does not fetch templates or cookbook files" do # Implicitly tested in previous test; this test is just for behavior specification. @server_api.should_not_receive(:get_rest). with('http://chef.example.com/ffffff', true) @synchronizer.sync_cookbooks end context "Chef::Config[:no_lazy_load] is true" do before do Chef::Config[:no_lazy_load] = true @synchronizer = Chef::CookbookSynchronizer.new(@cookbook_manifest, @events) @synchronizer.stub!(:server_api).and_return(@server_api) @synchronizer.stub!(:cache).and_return(@file_cache) @synchronizer.stub!(:clear_obsoleted_cookbooks) @cookbook_a_file_default_tempfile = mock("Tempfile for cookbook_a megaman.conf file", :path => "/tmp/cookbook_a_file_default_tempfile") @cookbook_a_template_default_tempfile = mock("Tempfile for cookbook_a apache.conf.erb template", :path => "/tmp/cookbook_a_template_default_tempfile") end after do Chef::Config[:no_lazy_load] = false end it "fetches templates and cookbook files" do @file_cache.should_receive(:has_key?). with("cookbooks/cookbook_a/files/default/megaman.conf"). and_return(false) @file_cache.should_receive(:has_key?). with("cookbooks/cookbook_a/templates/default/apache2.conf.erb"). and_return(false) @server_api.should_receive(:get_rest). with('http://chef.example.com/megaman.conf', true). and_return(@cookbook_a_file_default_tempfile) @file_cache.should_receive(:move_to). with("/tmp/cookbook_a_file_default_tempfile", "cookbooks/cookbook_a/files/default/megaman.conf") @file_cache.should_receive(:load). with("cookbooks/cookbook_a/files/default/megaman.conf", false). and_return("/file-cache/cookbooks/cookbook_a/default/megaman.conf") @server_api.should_receive(:get_rest). with('http://chef.example.com/ffffff', true). and_return(@cookbook_a_template_default_tempfile) @file_cache.should_receive(:move_to). with("/tmp/cookbook_a_template_default_tempfile", "cookbooks/cookbook_a/templates/default/apache2.conf.erb") @file_cache.should_receive(:load). with("cookbooks/cookbook_a/templates/default/apache2.conf.erb", false). and_return("/file-cache/cookbooks/cookbook_a/templates/default/apache2.conf.erb") @synchronizer.sync_cookbooks end end end context "when the cache contains outdated files" do before do # Files are in the cache: @file_cache.should_receive(:has_key?). with("cookbooks/cookbook_a/recipes/default.rb"). and_return(true) @file_cache.should_receive(:has_key?). with("cookbooks/cookbook_a/attributes/default.rb"). and_return(true) # Fetch and copy default.rb recipe @server_api.should_receive(:get_rest). with('http://chef.example.com/abc123', true). and_return(@cookbook_a_default_recipe_tempfile) @file_cache.should_receive(:move_to). with("/tmp/cookbook_a_recipes_default_rb", "cookbooks/cookbook_a/recipes/default.rb") @file_cache.should_receive(:load). with("cookbooks/cookbook_a/recipes/default.rb", false). twice. and_return("/file-cache/cookbooks/cookbook_a/recipes/default.rb") # Current file has fff000, want abc123 Chef::CookbookVersion.should_receive(:checksum_cookbook_file). with("/file-cache/cookbooks/cookbook_a/recipes/default.rb"). and_return("fff000") # Fetch and copy default.rb attribute file @server_api.should_receive(:get_rest). with('http://chef.example.com/abc456', true). and_return(@cookbook_a_default_attribute_tempfile) @file_cache.should_receive(:move_to). with("/tmp/cookbook_a_attributes_default_rb", "cookbooks/cookbook_a/attributes/default.rb") @file_cache.should_receive(:load). with("cookbooks/cookbook_a/attributes/default.rb", false). twice. and_return("/file-cache/cookbooks/cookbook_a/attributes/default.rb") # Current file has fff000, want abc456 Chef::CookbookVersion.should_receive(:checksum_cookbook_file). with("/file-cache/cookbooks/cookbook_a/attributes/default.rb"). and_return("fff000") end it "updates the outdated files" do @synchronizer.sync_cookbooks end end context "when the cache is up to date" do before do # Files are in the cache: @file_cache.should_receive(:has_key?). with("cookbooks/cookbook_a/recipes/default.rb"). and_return(true) @file_cache.should_receive(:has_key?). with("cookbooks/cookbook_a/attributes/default.rb"). and_return(true) # Current file has abc123, want abc123 Chef::CookbookVersion.should_receive(:checksum_cookbook_file). with("/file-cache/cookbooks/cookbook_a/recipes/default.rb"). and_return("abc123") # Current file has abc456, want abc456 Chef::CookbookVersion.should_receive(:checksum_cookbook_file). with("/file-cache/cookbooks/cookbook_a/attributes/default.rb"). and_return("abc456") @file_cache.should_receive(:load). with("cookbooks/cookbook_a/recipes/default.rb", false). twice. and_return("/file-cache/cookbooks/cookbook_a/recipes/default.rb") @file_cache.should_receive(:load). with("cookbooks/cookbook_a/attributes/default.rb", false). twice. and_return("/file-cache/cookbooks/cookbook_a/attributes/default.rb") end it "does not update files" do @file_cache.should_not_receive(:move_to) @server_api.should_not_receive(:get_rest) @synchronizer.sync_cookbooks end end end end chef-11.8.2/spec/unit/cookbook/syntax_check_spec.rb0000644000004100000410000001501512254362222022303 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require "chef/cookbook/syntax_check" describe Chef::Cookbook::SyntaxCheck do let(:cookbook_path) { File.join(CHEF_SPEC_DATA, 'cookbooks', 'openldap') } let(:syntax_check) { Chef::Cookbook::SyntaxCheck.new(cookbook_path) } before do Chef::Log.logger = Logger.new(StringIO.new) Chef::Log.level = :warn # suppress "Syntax OK" messages @attr_files = %w{default.rb smokey.rb}.map { |f| File.join(cookbook_path, 'attributes', f) } @defn_files = %w{client.rb server.rb}.map { |f| File.join(cookbook_path, 'definitions', f)} @recipes = %w{default.rb gigantor.rb one.rb}.map { |f| File.join(cookbook_path, 'recipes', f) } @ruby_files = @attr_files + @defn_files + @recipes + [File.join(cookbook_path, "metadata.rb")] basenames = %w{ helpers_via_partial_test.erb helper_test.erb openldap_stuff.conf.erb openldap_variable_stuff.conf.erb test.erb some_windows_line_endings.erb all_windows_line_endings.erb no_windows_line_endings.erb } @template_files = basenames.map { |f| File.join(cookbook_path, 'templates', 'default', f)} end it "creates a syntax checker given the cookbook name when Chef::Config.cookbook_path is set" do Chef::Config[:cookbook_path] = File.dirname(cookbook_path) syntax_check = Chef::Cookbook::SyntaxCheck.for_cookbook(:openldap) syntax_check.cookbook_path.should == cookbook_path end describe "when first created" do it "has the path to the cookbook to syntax check" do syntax_check.cookbook_path.should == cookbook_path end it "lists the ruby files in the cookbook" do syntax_check.ruby_files.sort.should == @ruby_files.sort end it "lists the erb templates in the cookbook" do syntax_check.template_files.sort.should == @template_files.sort end end describe "when validating cookbooks" do let(:cache_path) { Dir.mktmpdir } before do Chef::Config[:syntax_check_cache_path] = cache_path end after do FileUtils.rm_rf(cache_path) if File.exist?(cache_path) end describe "and the files have not been syntax checked previously" do it "shows that all ruby files require a syntax check" do syntax_check.untested_ruby_files.sort.should == @ruby_files.sort end it "shows that all template files require a syntax check" do syntax_check.untested_template_files.sort.should == @template_files.sort end it "removes a ruby file from the list of untested files after it is marked as validated" do recipe = File.join(cookbook_path, 'recipes', 'default.rb') syntax_check.validated(recipe) syntax_check.untested_ruby_files.should_not include(recipe) end it "removes a template file from the list of untested files after it is marked as validated" do template = File.join(cookbook_path, 'templates', 'default', 'test.erb') syntax_check.validated(template) syntax_check.untested_template_files.should_not include(template) end it "validates all ruby files" do syntax_check.validate_ruby_files.should be_true syntax_check.untested_ruby_files.should be_empty end it "validates all templates" do syntax_check.validate_templates.should be_true syntax_check.untested_template_files.should be_empty end describe "and a file has a syntax error" do before do cookbook_path = File.join(CHEF_SPEC_DATA, 'cookbooks', 'borken') syntax_check.cookbook_path.replace(cookbook_path) end it "it indicates that a ruby file has a syntax error" do syntax_check.validate_ruby_files.should be_false end it "does not remove the invalid file from the list of untested files" do syntax_check.untested_ruby_files.should include(File.join(cookbook_path, 'recipes', 'default.rb')) lambda { syntax_check.validate_ruby_files }.should_not change(syntax_check, :untested_ruby_files) end it "indicates that a template file has a syntax error" do syntax_check.validate_templates.should be_false end it "does not remove the invalid template from the list of untested templates" do syntax_check.untested_template_files.should include(File.join(cookbook_path, 'templates', 'default', 'borken.erb')) lambda {syntax_check.validate_templates}.should_not change(syntax_check, :untested_template_files) end end describe "and an ignored file has a syntax error" do before do cookbook_path = File.join(CHEF_SPEC_DATA, 'cookbooks', 'ignorken') Chef::Config[:cookbook_path] = File.dirname(cookbook_path) syntax_check.cookbook_path.replace(cookbook_path) @ruby_files = [File.join(cookbook_path, 'recipes/default.rb')] end it "shows that ignored ruby files do not require a syntax check" do syntax_check.untested_ruby_files.sort.should == @ruby_files.sort end it "does not indicate that a ruby file has a syntax error" do syntax_check.validate_ruby_files.should be_true syntax_check.untested_ruby_files.should be_empty end end end describe "and the files have been syntax checked previously" do before do syntax_check.untested_ruby_files.each { |f| syntax_check.validated(f) } syntax_check.untested_template_files.each { |f| syntax_check.validated(f) } end it "does not syntax check ruby files" do syntax_check.should_not_receive(:shell_out) syntax_check.validate_ruby_files.should be_true end it "does not syntax check templates" do syntax_check.should_not_receive(:shell_out) syntax_check.validate_templates.should be_true end end end end chef-11.8.2/spec/unit/cookbook/chefignore_spec.rb0000644000004100000410000000262412254362222021733 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Cookbook::Chefignore do before do @chefignore = Chef::Cookbook::Chefignore.new(File.join(CHEF_SPEC_DATA, 'cookbooks')) end it "loads the globs in the chefignore file" do @chefignore.ignores.should =~ %w[recipes/ignoreme.rb ignored] end it "removes items from an array that match the ignores" do file_list = %w[ recipes/ignoreme.rb recipes/dontignoreme.rb ] @chefignore.remove_ignores_from(file_list).should == %w[recipes/dontignoreme.rb] end it "determines if a file is ignored" do @chefignore.ignored?('ignored').should be_true @chefignore.ignored?('recipes/ignoreme.rb').should be_true @chefignore.ignored?('recipes/dontignoreme.rb').should be_false end end chef-11.8.2/spec/unit/cookbook/metadata_spec.rb0000644000004100000410000005112112254362222021376 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Seth Falcon () # Copyright:: Copyright 2008-2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/cookbook/metadata' describe Chef::Cookbook::Metadata do before(:each) do @cookbook = Chef::CookbookVersion.new('test_cookbook') @meta = Chef::Cookbook::Metadata.new(@cookbook) end describe "when comparing for equality" do before do @fields = [ :name, :description, :long_description, :maintainer, :maintainer_email, :license, :platforms, :dependencies, :recommendations, :suggestions, :conflicting, :providing, :replacing, :attributes, :groupings, :recipes, :version] end it "does not depend on object identity for equality" do @meta.should == @meta.dup end it "is not equal to another object if it isn't have all of the metadata fields" do @fields.each_index do |field_to_remove| fields_to_include = @fields.dup fields_to_include.delete_at(field_to_remove) almost_duck_type = Struct.new(*fields_to_include).new @fields.each do |field| setter = "#{field}=" metadata_value = @meta.send(field) almost_duck_type.send(setter, metadata_value) if almost_duck_type.respond_to?(setter) @mets.should_not == almost_duck_type end end end it "is equal to another object if it has equal values for all metadata fields" do duck_type = Struct.new(*@fields).new @fields.each do |field| setter = "#{field}=" metadata_value = @meta.send(field) duck_type.send(setter, metadata_value) end @meta.should == duck_type end it "is not equal if any values are different" do duck_type_class = Struct.new(*@fields) @fields.each do |field_to_change| duck_type = duck_type_class.new @fields.each do |field| setter = "#{field}=" metadata_value = @meta.send(field) duck_type.send(setter, metadata_value) end field_to_change duck_type.send("#{field_to_change}=".to_sym, :epic_fail) @meta.should_not == duck_type end end end describe "when first created" do it "should return a Chef::Cookbook::Metadata object" do @meta.should be_a_kind_of(Chef::Cookbook::Metadata) end it "should allow a cookbook as the first argument" do lambda { Chef::Cookbook::Metadata.new(@cookbook) }.should_not raise_error end it "should allow an maintainer name for the second argument" do lambda { Chef::Cookbook::Metadata.new(@cookbook, 'Bobo T. Clown') }.should_not raise_error end it "should set the maintainer name from the second argument" do md = Chef::Cookbook::Metadata.new(@cookbook, 'Bobo T. Clown') md.maintainer.should == 'Bobo T. Clown' end it "should allow an maintainer email for the third argument" do lambda { Chef::Cookbook::Metadata.new(@cookbook, 'Bobo T. Clown', 'bobo@clown.co') }.should_not raise_error end it "should set the maintainer email from the third argument" do md = Chef::Cookbook::Metadata.new(@cookbook, 'Bobo T. Clown', 'bobo@clown.co') md.maintainer_email.should == 'bobo@clown.co' end it "should allow a license for the fourth argument" do lambda { Chef::Cookbook::Metadata.new(@cookbook, 'Bobo T. Clown', 'bobo@clown.co', 'Clown License v1') }.should_not raise_error end it "should set the license from the fourth argument" do md = Chef::Cookbook::Metadata.new(@cookbook, 'Bobo T. Clown', 'bobo@clown.co', 'Clown License v1') md.license.should == 'Clown License v1' end end describe "cookbook" do it "should return the cookbook we were initialized with" do @meta.cookbook.should eql(@cookbook) end end describe "name" do it "should return the name of the cookbook" do @meta.name.should eql(@cookbook.name) end end describe "platforms" do it "should return the current platform hash" do @meta.platforms.should be_a_kind_of(Hash) end end describe "adding a supported platform" do it "should support adding a supported platform with a single expression" do @meta.supports("ubuntu", ">= 8.04") @meta.platforms["ubuntu"].should == '>= 8.04' end end describe "meta-data attributes" do params = { :maintainer => "Adam Jacob", :maintainer_email => "adam@opscode.com", :license => "Apache v2.0", :description => "Foobar!", :long_description => "Much Longer\nSeriously", :version => "0.6.0" } params.sort { |a,b| a.to_s <=> b.to_s }.each do |field, field_value| describe field do it "should be set-able via #{field}" do @meta.send(field, field_value).should eql(field_value) end it "should be get-able via #{field}" do @meta.send(field, field_value) @meta.send(field).should eql(field_value) end end end describe "version transformation" do it "should transform an '0.6' version to '0.6.0'" do @meta.send(:version, "0.6").should eql("0.6.0") end it "should spit out '0.6.0' after transforming '0.6'" do @meta.send(:version, "0.6") @meta.send(:version).should eql("0.6.0") end end end describe "describing dependencies" do dep_types = { :depends => [ :dependencies, "foo::bar", "> 0.2" ], :recommends => [ :recommendations, "foo::bar", ">= 0.2" ], :suggests => [ :suggestions, "foo::bar", "> 0.2" ], :conflicts => [ :conflicting, "foo::bar", "~> 0.2" ], :provides => [ :providing, "foo::bar", "<= 0.2" ], :replaces => [ :replacing, "foo::bar", "= 0.2.1" ], } dep_types.sort { |a,b| a.to_s <=> b.to_s }.each do |dep, dep_args| check_with = dep_args.shift describe dep do it "should be set-able via #{dep}" do @meta.send(dep, *dep_args).should == dep_args[1] end it "should be get-able via #{check_with}" do @meta.send(dep, *dep_args) @meta.send(check_with).should == { dep_args[0] => dep_args[1] } end end end describe "in the obsoleted format" do dep_types = { :depends => [ "foo::bar", "> 0.2", "< 1.0" ], :recommends => [ "foo::bar", ">= 0.2", "< 1.0" ], :suggests => [ "foo::bar", "> 0.2", "< 1.0" ], :conflicts => [ "foo::bar", "> 0.2", "< 1.0" ], :provides => [ "foo::bar", "> 0.2", "< 1.0" ], :replaces => [ "foo::bar", "> 0.2.1", "< 1.0" ], } dep_types.each do |dep, dep_args| it "for #{dep} raises an informative error instead of vomiting on your shoes" do lambda {@meta.send(dep, *dep_args)}.should raise_error(Chef::Exceptions::ObsoleteDependencySyntax) end end end describe "with obsolete operators" do dep_types = { :depends => [ "foo::bar", ">> 0.2"], :recommends => [ "foo::bar", ">> 0.2"], :suggests => [ "foo::bar", ">> 0.2"], :conflicts => [ "foo::bar", ">> 0.2"], :provides => [ "foo::bar", ">> 0.2"], :replaces => [ "foo::bar", ">> 0.2.1"], } dep_types.each do |dep, dep_args| it "for #{dep} raises an informative error instead of vomiting on your shoes" do lambda {@meta.send(dep, *dep_args)}.should raise_error(Chef::Exceptions::InvalidVersionConstraint) end end end end describe "attribute groupings" do it "should allow you set a grouping" do group = { "title" => "MySQL Tuning", "description" => "Setting from the my.cnf file that allow you to tune your mysql server" } @meta.grouping("/db/mysql/databases/tuning", group).should == group end it "should not accept anything but a string for display_name" do lambda { @meta.grouping("db/mysql/databases", :title => "foo") }.should_not raise_error(ArgumentError) lambda { @meta.grouping("db/mysql/databases", :title => Hash.new) }.should raise_error(ArgumentError) end it "should not accept anything but a string for the description" do lambda { @meta.grouping("db/mysql/databases", :description => "foo") }.should_not raise_error(ArgumentError) lambda { @meta.grouping("db/mysql/databases", :description => Hash.new) }.should raise_error(ArgumentError) end end describe "cookbook attributes" do it "should allow you set an attributes metadata" do attrs = { "display_name" => "MySQL Databases", "description" => "Description of MySQL", "choice" => ['dedicated', 'shared'], "calculated" => false, "type" => 'string', "required" => 'recommended', "recipes" => [ "mysql::server", "mysql::master" ], "default" => [ ] } @meta.attribute("/db/mysql/databases", attrs).should == attrs end it "should not accept anything but a string for display_name" do lambda { @meta.attribute("db/mysql/databases", :display_name => "foo") }.should_not raise_error(ArgumentError) lambda { @meta.attribute("db/mysql/databases", :display_name => Hash.new) }.should raise_error(ArgumentError) end it "should not accept anything but a string for the description" do lambda { @meta.attribute("db/mysql/databases", :description => "foo") }.should_not raise_error(ArgumentError) lambda { @meta.attribute("db/mysql/databases", :description => Hash.new) }.should raise_error(ArgumentError) end it "should not accept anything but an array of strings for choice" do lambda { @meta.attribute("db/mysql/databases", :choice => ['dedicated', 'shared']) }.should_not raise_error(ArgumentError) lambda { @meta.attribute("db/mysql/databases", :choice => [10, 'shared']) }.should raise_error(ArgumentError) lambda { @meta.attribute("db/mysql/databases", :choice => Hash.new) }.should raise_error(ArgumentError) end it "should set choice to empty array by default" do @meta.attribute("db/mysql/databases", {}) @meta.attributes["db/mysql/databases"][:choice].should == [] end it "should let calculated be true or false" do lambda { @meta.attribute("db/mysql/databases", :calculated => true) }.should_not raise_error(ArgumentError) lambda { @meta.attribute("db/mysql/databases", :calculated => false) }.should_not raise_error(ArgumentError) lambda { @meta.attribute("db/mysql/databases", :calculated => Hash.new) }.should raise_error(ArgumentError) end it "should set calculated to false by default" do @meta.attribute("db/mysql/databases", {}) @meta.attributes["db/mysql/databases"][:calculated].should == false end it "accepts String for the attribute type" do lambda { @meta.attribute("db/mysql/databases", :type => "string") }.should_not raise_error(ArgumentError) end it "accepts Array for the attribute type" do lambda { @meta.attribute("db/mysql/databases", :type => "array") }.should_not raise_error(ArgumentError) lambda { @meta.attribute("db/mysql/databases", :type => Array.new) }.should raise_error(ArgumentError) end it "accepts symbol for the attribute type" do lambda { @meta.attribute("db/mysql/databases", :type => "symbol") }.should_not raise_error(ArgumentError) end it "should let type be hash (backwards compatability only)" do lambda { @meta.attribute("db/mysql/databases", :type => "hash") }.should_not raise_error(ArgumentError) end it "should let required be required, recommended or optional" do lambda { @meta.attribute("db/mysql/databases", :required => 'required') }.should_not raise_error(ArgumentError) lambda { @meta.attribute("db/mysql/databases", :required => 'recommended') }.should_not raise_error(ArgumentError) lambda { @meta.attribute("db/mysql/databases", :required => 'optional') }.should_not raise_error(ArgumentError) end it "should convert required true to required" do lambda { @meta.attribute("db/mysql/databases", :required => true) }.should_not raise_error(ArgumentError) #attrib = @meta.attributes["db/mysql/databases"][:required].should == "required" end it "should convert required false to optional" do lambda { @meta.attribute("db/mysql/databases", :required => false) }.should_not raise_error(ArgumentError) #attrib = @meta.attributes["db/mysql/databases"][:required].should == "optional" end it "should set required to 'optional' by default" do @meta.attribute("db/mysql/databases", {}) @meta.attributes["db/mysql/databases"][:required].should == 'optional' end it "should make sure recipes is an array" do lambda { @meta.attribute("db/mysql/databases", :recipes => []) }.should_not raise_error(ArgumentError) lambda { @meta.attribute("db/mysql/databases", :required => Hash.new) }.should raise_error(ArgumentError) end it "should set recipes to an empty array by default" do @meta.attribute("db/mysql/databases", {}) @meta.attributes["db/mysql/databases"][:recipes].should == [] end it "should allow the default value to be a string, array, or hash" do lambda { @meta.attribute("db/mysql/databases", :default => []) }.should_not raise_error(ArgumentError) lambda { @meta.attribute("db/mysql/databases", :default => {}) }.should_not raise_error(ArgumentError) lambda { @meta.attribute("db/mysql/databases", :default => "alice in chains") }.should_not raise_error(ArgumentError) lambda { @meta.attribute("db/mysql/databases", :required => :not_gonna_do_it) }.should raise_error(ArgumentError) end it "should error if default used with calculated" do lambda { attrs = { :calculated => true, :default => [ "I thought you said calculated" ] } @meta.attribute("db/mysql/databases", attrs) }.should raise_error(ArgumentError) lambda { attrs = { :calculated => true, :default => "I thought you said calculated" } @meta.attribute("db/mysql/databases", attrs) }.should raise_error(ArgumentError) end it "should allow a default that is a choice" do lambda { attrs = { :choice => [ "a", "b", "c"], :default => "b" } @meta.attribute("db/mysql/databases", attrs) }.should_not raise_error(ArgumentError) lambda { attrs = { :choice => [ "a", "b", "c", "d", "e"], :default => ["b", "d"] } @meta.attribute("db/mysql/databases", attrs) }.should_not raise_error(ArgumentError) end it "should error if default is not a choice" do lambda { attrs = { :choice => [ "a", "b", "c"], :default => "d" } @meta.attribute("db/mysql/databases", attrs) }.should raise_error(ArgumentError) lambda { attrs = { :choice => [ "a", "b", "c", "d", "e"], :default => ["b", "z"] } @meta.attribute("db/mysql/databases", attrs) }.should raise_error(ArgumentError) end end describe "recipes" do before(:each) do @cookbook.recipe_files = [ "default.rb", "enlighten.rb" ] @meta = Chef::Cookbook::Metadata.new(@cookbook) end it "should have the names of the recipes" do @meta.recipes["test_cookbook"].should == "" @meta.recipes["test_cookbook::enlighten"].should == "" end it "should let you set the description for a recipe" do @meta.recipe "test_cookbook", "It, um... tests stuff?" @meta.recipes["test_cookbook"].should == "It, um... tests stuff?" end it "should automatically provide each recipe" do @meta.providing.has_key?("test_cookbook").should == true @meta.providing.has_key?("test_cookbook::enlighten").should == true end end describe "json" do before(:each) do @cookbook.recipe_files = [ "default.rb", "enlighten.rb" ] @meta = Chef::Cookbook::Metadata.new(@cookbook) @meta.version "1.0" @meta.maintainer "Bobo T. Clown" @meta.maintainer_email "bobo@example.com" @meta.long_description "I have a long arm!" @meta.supports :ubuntu, "> 8.04" @meta.depends "bobo", "= 1.0" @meta.depends "bobotclown", "= 1.1" @meta.recommends "snark", "< 3.0" @meta.suggests "kindness", "> 2.0" @meta.conflicts "hatred" @meta.provides "foo(:bar, :baz)" @meta.replaces "snarkitron" @meta.recipe "test_cookbook::enlighten", "is your buddy" @meta.attribute "bizspark/has_login", :display_name => "You have nothing" @meta.version "1.2.3" end describe "serialize" do before(:each) do @serial = Chef::JSONCompat.from_json(@meta.to_json) end it "should serialize to a json hash" do Chef::JSONCompat.from_json(@meta.to_json).should be_a_kind_of(Hash) end %w{ name description long_description maintainer maintainer_email license platforms dependencies suggestions recommendations conflicting providing replacing attributes recipes version }.each do |t| it "should include '#{t}'" do @serial[t].should == @meta.send(t.to_sym) end end end describe "deserialize" do before(:each) do @deserial = Chef::Cookbook::Metadata.from_json(@meta.to_json) end it "should deserialize to a Chef::Cookbook::Metadata object" do @deserial.should be_a_kind_of(Chef::Cookbook::Metadata) end %w{ name description long_description maintainer maintainer_email license platforms dependencies suggestions recommendations conflicting providing replacing attributes recipes version }.each do |t| it "should match '#{t}'" do @deserial.send(t.to_sym).should == @meta.send(t.to_sym) end end end describe "from_hash" do before(:each) do @hash = @meta.to_hash end [:dependencies, :recommendations, :suggestions, :conflicting, :replacing].each do |to_check| it "should transform deprecated greater than syntax for :#{to_check.to_s}" do @hash[to_check.to_s]["foo::bar"] = ">> 0.2" deserial = Chef::Cookbook::Metadata.from_hash(@hash) deserial.send(to_check)["foo::bar"].should == '> 0.2' end it "should transform deprecated less than syntax for :#{to_check.to_s}" do @hash[to_check.to_s]["foo::bar"] = "<< 0.2" deserial = Chef::Cookbook::Metadata.from_hash(@hash) deserial.send(to_check)["foo::bar"].should == '< 0.2' end it "should ignore multiple dependency constraints for :#{to_check.to_s}" do @hash[to_check.to_s]["foo::bar"] = [ ">= 1.0", "<= 5.2" ] deserial = Chef::Cookbook::Metadata.from_hash(@hash) deserial.send(to_check)["foo::bar"].should == [] end it "should accept an empty array of dependency constraints for :#{to_check.to_s}" do @hash[to_check.to_s]["foo::bar"] = [] deserial = Chef::Cookbook::Metadata.from_hash(@hash) deserial.send(to_check)["foo::bar"].should == [] end it "should accept single-element arrays of dependency constraints for :#{to_check.to_s}" do @hash[to_check.to_s]["foo::bar"] = [ ">= 2.0" ] deserial = Chef::Cookbook::Metadata.from_hash(@hash) deserial.send(to_check)["foo::bar"].should == ">= 2.0" end end end end end chef-11.8.2/spec/unit/search/0000755000004100000410000000000012254362222015716 5ustar www-datawww-datachef-11.8.2/spec/unit/search/query_spec.rb0000644000004100000410000000717112254362222020430 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009,2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/search/query' describe Chef::Search::Query do before(:each) do @rest = mock("Chef::REST") Chef::REST.stub!(:new).and_return(@rest) @query = Chef::Search::Query.new end describe "search" do before(:each) do @response = { "rows" => [ { "id" => "for you" }, { "id" => "hip hop" }, { "id" => "thought was down by law for you" }, { "id" => "kept it hard core for you" }, ], "start" => 0, "total" => 4 } @rest.stub!(:get_rest).and_return(@response) end it "should accept a type as the first argument" do lambda { @query.search("foo") }.should_not raise_error(ArgumentError) lambda { @query.search(:foo) }.should_not raise_error(ArgumentError) lambda { @query.search(Hash.new) }.should raise_error(ArgumentError) end it "should query for every object of a type by default" do @rest.should_receive(:get_rest).with("search/foo?q=*:*&sort=X_CHEF_id_CHEF_X%20asc&start=0&rows=1000").and_return(@response) @query = Chef::Search::Query.new @query.search(:foo) end it "should allow a custom query" do @rest.should_receive(:get_rest).with("search/foo?q=gorilla:dundee&sort=X_CHEF_id_CHEF_X%20asc&start=0&rows=1000").and_return(@response) @query = Chef::Search::Query.new @query.search(:foo, "gorilla:dundee") end it "should let you set a sort order" do @rest.should_receive(:get_rest).with("search/foo?q=gorilla:dundee&sort=id%20desc&start=0&rows=1000").and_return(@response) @query = Chef::Search::Query.new @query.search(:foo, "gorilla:dundee", "id desc") end it "should let you set a starting object" do @rest.should_receive(:get_rest).with("search/foo?q=gorilla:dundee&sort=id%20desc&start=2&rows=1000").and_return(@response) @query = Chef::Search::Query.new @query.search(:foo, "gorilla:dundee", "id desc", 2) end it "should let you set how many rows to return" do @rest.should_receive(:get_rest).with("search/foo?q=gorilla:dundee&sort=id%20desc&start=2&rows=40").and_return(@response) @query = Chef::Search::Query.new @query.search(:foo, "gorilla:dundee", "id desc", 2, 40) end it "should return the raw rows, start, and total if no block is passed" do rows, start, total = @query.search(:foo) rows.should equal(@response["rows"]) start.should equal(@response["start"]) total.should equal(@response["total"]) end it "should call a block for each object in the response" do @call_me = mock("blocky") @response["rows"].each { |r| @call_me.should_receive(:do).with(r) } @query.search(:foo) { |r| @call_me.do(r) } end it "should page through the responses" do @call_me = mock("blocky") @response["rows"].each { |r| @call_me.should_receive(:do).with(r) } @query.search(:foo, "*:*", nil, 0, 1) { |r| @call_me.do(r) } end end end chef-11.8.2/spec/unit/data_bag_spec.rb0000644000004100000410000001325312254362222017536 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/data_bag' describe Chef::DataBag do before(:each) do @data_bag = Chef::DataBag.new end describe "initialize" do it "should be a Chef::DataBag" do @data_bag.should be_a_kind_of(Chef::DataBag) end end describe "name" do it "should let you set the name to a string" do @data_bag.name("clowns").should == "clowns" end it "should return the current name" do @data_bag.name "clowns" @data_bag.name.should == "clowns" end it "should not accept spaces" do lambda { @data_bag.name "clown masters" }.should raise_error(ArgumentError) end it "should throw an ArgumentError if you feed it anything but a string" do lambda { @data_bag.name Hash.new }.should raise_error(ArgumentError) end end describe "deserialize" do before(:each) do @data_bag.name('mars_volta') @deserial = Chef::JSONCompat.from_json(@data_bag.to_json) end it "should deserialize to a Chef::DataBag object" do @deserial.should be_a_kind_of(Chef::DataBag) end %w{ name }.each do |t| it "should match '#{t}'" do @deserial.send(t.to_sym).should == @data_bag.send(t.to_sym) end end end describe "when saving" do before do @data_bag.name('piggly_wiggly') @rest = mock("Chef::REST") Chef::REST.stub!(:new).and_return(@rest) end it "should silently proceed when the data bag already exists" do exception = mock("409 error", :code => "409") @rest.should_receive(:post_rest).and_raise(Net::HTTPServerException.new("foo", exception)) @data_bag.save end it "should create the data bag" do @rest.should_receive(:post_rest).with("data", @data_bag) @data_bag.save end describe "when whyrun mode is enabled" do before do Chef::Config[:why_run] = true end after do Chef::Config[:why_run] = false end it "should not save" do @rest.should_not_receive(:post_rest) @data_bag.save end end end describe "when loading" do describe "from an API call" do before do Chef::Config[:chef_server_url] = 'https://myserver.example.com' @http_client = mock('Chef::REST') end it "should get the data bag from the server" do Chef::REST.should_receive(:new).with('https://myserver.example.com').and_return(@http_client) @http_client.should_receive(:get_rest).with('data/foo') Chef::DataBag.load('foo') end it "should return the data bag" do Chef::REST.stub!(:new).and_return(@http_client) @http_client.should_receive(:get_rest).with('data/foo').and_return({'bar' => 'https://myserver.example.com/data/foo/bar'}) data_bag = Chef::DataBag.load('foo') data_bag.should == {'bar' => 'https://myserver.example.com/data/foo/bar'} end end describe "in solo mode" do before do Chef::Config[:solo] = true Chef::Config[:data_bag_path] = '/var/chef/data_bags' end after do Chef::Config[:solo] = false end it "should get the data bag from the data_bag_path" do File.should_receive(:directory?).with('/var/chef/data_bags').and_return(true) Dir.should_receive(:glob).with('/var/chef/data_bags/foo/*.json').and_return([]) Chef::DataBag.load('foo') end it "should get the data bag from the data_bag_path by symbolic name" do File.should_receive(:directory?).with('/var/chef/data_bags').and_return(true) Dir.should_receive(:glob).with('/var/chef/data_bags/foo/*.json').and_return([]) Chef::DataBag.load(:foo) end it "should return the data bag" do File.should_receive(:directory?).with('/var/chef/data_bags').and_return(true) Dir.stub!(:glob).and_return(["/var/chef/data_bags/foo/bar.json", "/var/chef/data_bags/foo/baz.json"]) IO.should_receive(:read).with('/var/chef/data_bags/foo/bar.json').and_return('{"id": "bar", "name": "Bob Bar" }') IO.should_receive(:read).with('/var/chef/data_bags/foo/baz.json').and_return('{"id": "baz", "name": "John Baz" }') data_bag = Chef::DataBag.load('foo') data_bag.should == { 'bar' => { 'id' => 'bar', 'name' => 'Bob Bar' }, 'baz' => { 'id' => 'baz', 'name' => 'John Baz' }} end it "should return the data bag list" do File.should_receive(:directory?).with('/var/chef/data_bags').and_return(true) Dir.should_receive(:glob).and_return(["/var/chef/data_bags/foo", "/var/chef/data_bags/bar"]) data_bag_list = Chef::DataBag.list data_bag_list.should == { 'bar' => 'bar', 'foo' => 'foo' } end it 'should raise an error if the configured data_bag_path is invalid' do File.should_receive(:directory?).with('/var/chef/data_bags').and_return(false) lambda { Chef::DataBag.load('foo') }.should raise_error Chef::Exceptions::InvalidDataBagPath, "Data bag path '/var/chef/data_bags' is invalid" end end end end chef-11.8.2/spec/unit/file_content_management/0000755000004100000410000000000012254362222021316 5ustar www-datawww-datachef-11.8.2/spec/unit/file_content_management/deploy/0000755000004100000410000000000012254362222022612 5ustar www-datawww-datachef-11.8.2/spec/unit/file_content_management/deploy/cp_spec.rb0000644000004100000410000000253512254362222024560 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::FileContentManagement::Deploy::Cp do let(:content_deployer) { described_class.new } let(:target_file_path) { "/etc/my_app.conf" } describe "creating the file" do it "touches the file to create it" do FileUtils.should_receive(:touch).with(target_file_path) content_deployer.create(target_file_path) end end describe "updating the file" do let(:staging_file_path) { "/tmp/random-dir/staging-file.tmp" } it "copies the staging file's content" do FileUtils.should_receive(:cp).with(staging_file_path, target_file_path) content_deployer.deploy(staging_file_path, target_file_path) end end end chef-11.8.2/spec/unit/file_content_management/deploy/mv_unix_spec.rb0000644000004100000410000000725112254362222025643 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::FileContentManagement::Deploy::MvUnix do let(:content_deployer) { described_class.new } let(:target_file_path) { "/etc/my_app.conf" } describe "creating the file" do it "touches the file to create it" do FileUtils.should_receive(:touch).with(target_file_path) content_deployer.create(target_file_path) end end describe "updating the file" do let(:staging_file_path) { "/tmp/random-dir/staging-file.tmp" } let(:target_file_mode) { 0644 } let(:target_file_stat) do mock "File::Stat struct for target file", :mode => target_file_mode, :uid => target_file_uid, :gid => target_file_gid end before do File.should_receive(:stat).with(target_file_path).and_return(target_file_stat) File.should_receive(:chmod).with(target_file_mode, staging_file_path).and_return(1) FileUtils.should_receive(:mv).with(staging_file_path, target_file_path) end # This context represents the case where: # * Chef runs as root # * The owner and group of the target file match the owner and group of the # staging file. context "when the user has permissions to set file ownership" do # For the purposes of this test, the uid/gid can be anything. These # values are just chosen because (assuming chef-client's euid == 1001 and # egid == 1001), the `chown` call is allowed by the OS. See the # description of `EPERM` in `man 2 chown` for reference. let(:target_file_uid) { 1001 } let(:target_file_gid) { 1001 } before do File.should_receive(:chown).with(target_file_uid, nil, staging_file_path).and_return(1) File.should_receive(:chown).with(nil, target_file_gid, staging_file_path).and_return(1) end it "fixes up permissions and moves the file into place" do content_deployer.deploy(staging_file_path, target_file_path) end end context "when the user does not have permissions to set file ownership" do # The test code does not care what these values are. These values are # chosen because they're representitive of the case that chef-client is # running as non-root and is managing a file that got ownership set to # root somehow. In this example, gid==20 is something like "staff" which # the user running chef-client is a member of (but it's not that user's # primary group). let(:target_file_uid) { 0 } let(:target_file_gid) { 20 } before do File.should_receive(:chown).with(target_file_uid, nil, staging_file_path).and_raise(Errno::EPERM) File.should_receive(:chown).with(nil, target_file_gid, staging_file_path).and_raise(Errno::EPERM) Chef::Log.should_receive(:warn).with(/^Could not set uid/) Chef::Log.should_receive(:warn).with(/^Could not set gid/) end it "fixes up permissions and moves the file into place" do content_deployer.deploy(staging_file_path, target_file_path) end end end end chef-11.8.2/spec/unit/file_content_management/deploy/mv_windows_spec.rb0000644000004100000410000001405312254362222026350 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' unless Chef::Platform.windows? class Chef module ReservedNames module Win32 module Security ACL = Object.new SecurableObject = Object.new end end end end end require 'chef/file_content_management/deploy/mv_windows' describe Chef::FileContentManagement::Deploy::MvWindows do let(:content_deployer) { described_class.new } let(:target_file_path) { "/etc/my_app.conf" } describe "creating the file" do it "touches the file to create it" do FileUtils.should_receive(:touch).with(target_file_path) content_deployer.create(target_file_path) end end describe "updating the file" do let(:staging_file_path) { "/tmp/random-dir/staging-file.tmp" } let(:target_file_security_object) do mock "Securable Object for target file" end let(:updated_target_security_object) do mock "Securable Object for target file after staging file deploy" end before do Chef::ReservedNames::Win32::Security::SecurableObject. stub(:new). with(target_file_path). and_return(target_file_security_object, updated_target_security_object) end context "when run without adminstrator privileges" do before do target_file_security_object.should_receive(:security_descriptor).and_raise(Chef::Exceptions::Win32APIError) end it "errors out with a WindowsNotAdmin error" do lambda { content_deployer.deploy(staging_file_path, target_file_path)}.should raise_error(Chef::Exceptions::WindowsNotAdmin) end end context "when run with administrator privileges" do let(:original_target_file_owner) { mock("original target file owner") } let(:original_target_file_group) { mock("original target file group") } let(:target_file_security_descriptor) do mock "security descriptor for target file", :group => original_target_file_group, :owner => original_target_file_owner end let(:updated_target_security_descriptor) do mock "security descriptor for target file" end before do target_file_security_object.stub(:security_descriptor).and_return(target_file_security_descriptor) FileUtils.should_receive(:mv).with(staging_file_path, target_file_path) updated_target_security_object.should_receive(:group=).with(original_target_file_group) updated_target_security_object.should_receive(:owner=).with(original_target_file_owner) end context "and the target file has no dacl or sacl" do before do target_file_security_descriptor.stub(:dacl_present?).and_return(false) target_file_security_descriptor.stub(:sacl_present?).and_return(false) end it "fixes up permissions and moves the file into place" do content_deployer.deploy(staging_file_path, target_file_path) end end context "and the target has a dacl and sacl" do let(:inherited_dacl_ace) { mock("Windows dacl ace (inherited)", :inherited? => true) } let(:not_inherited_dacl_ace) { mock("Windows dacl ace (not inherited)", :inherited? => false) } let(:original_target_file_dacl) { [inherited_dacl_ace, not_inherited_dacl_ace] } let(:inherited_sacl_ace) { mock("Windows sacl ace (inherited)", :inherited? => true) } let(:not_inherited_sacl_ace) { mock("Windows sacl ace (not inherited)", :inherited? => false) } let(:original_target_file_sacl) { [inherited_sacl_ace, not_inherited_sacl_ace] } let(:custom_dacl) { mock("Windows ACL for non-inherited dacl aces") } let(:custom_sacl) { mock("Windows ACL for non-inherited sacl aces") } before do target_file_security_descriptor.stub(:dacl_present?).and_return(true) target_file_security_descriptor.stub(:dacl_inherits?).and_return(dacl_inherits?) target_file_security_descriptor.stub(:dacl).and_return(original_target_file_dacl) Chef::ReservedNames::Win32::Security::ACL. should_receive(:create). with([not_inherited_dacl_ace]). and_return(custom_dacl) target_file_security_descriptor.stub(:sacl_present?).and_return(true) target_file_security_descriptor.stub(:sacl_inherits?).and_return(sacl_inherits?) target_file_security_descriptor.stub(:sacl).and_return(original_target_file_sacl) Chef::ReservedNames::Win32::Security::ACL. should_receive(:create). with([not_inherited_sacl_ace]). and_return(custom_sacl) updated_target_security_object.should_receive(:set_dacl).with(custom_dacl, dacl_inherits?) updated_target_security_object.should_receive(:set_sacl).with(custom_sacl, sacl_inherits?) end context "and the dacl and sacl don't inherit" do let(:dacl_inherits?) { false } let(:sacl_inherits?) { false } it "fixes up permissions and moves the file into place" do content_deployer.deploy(staging_file_path, target_file_path) end end context "and the dacl and sacl inherit" do let(:dacl_inherits?) { true } let(:sacl_inherits?) { true } it "fixes up permissions and moves the file into place" do content_deployer.deploy(staging_file_path, target_file_path) end end end end end end chef-11.8.2/spec/unit/file_cache_spec.rb0000644000004100000410000000715112254362222020056 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::FileCache do before do @file_cache_path = Dir.mktmpdir Chef::Config[:file_cache_path] = @file_cache_path @io = StringIO.new end after do FileUtils.rm_rf(Chef::Config[:file_cache_path]) end describe "when the relative path to the cache file doesn't exist" do it "creates intermediate directories as needed" do Chef::FileCache.store("whiz/bang", "I found a poop") File.should exist(File.join(@file_cache_path, 'whiz')) end it "creates the cached file at the correct relative path" do File.should_receive(:open).with(File.join(@file_cache_path, 'whiz', 'bang'), "w",416).and_yield(@io) Chef::FileCache.store("whiz/bang", "borkborkbork") end end describe "when storing a file" do before do File.stub!(:open).and_yield(@io) end it "should print the contents to the file" do Chef::FileCache.store("whiz/bang", "borkborkbork") @io.string.should == "borkborkbork" end end describe "when loading cached files" do it "finds and reads the cached file" do FileUtils.mkdir_p(File.join(@file_cache_path, 'whiz')) File.open(File.join(@file_cache_path, 'whiz', 'bang'), 'w') { |f| f.print("borkborkbork") } Chef::FileCache.load('whiz/bang').should == 'borkborkbork' end it "should raise a Chef::Exceptions::FileNotFound if the file doesn't exist" do lambda { Chef::FileCache.load('whiz/bang') }.should raise_error(Chef::Exceptions::FileNotFound) end end describe "when deleting cached files" do before(:each) do FileUtils.mkdir_p(File.join(@file_cache_path, 'whiz')) File.open(File.join(@file_cache_path, 'whiz', 'bang'), 'w') { |f| f.print("borkborkbork") } end it "unlinks the file" do Chef::FileCache.delete("whiz/bang") File.should_not exist(File.join(@file_cache_path, 'whiz', 'bang')) end end describe "when listing files in the cache" do before(:each) do FileUtils.mkdir_p(File.join(@file_cache_path, 'whiz')) FileUtils.touch(File.join(@file_cache_path, 'whiz', 'bang')) FileUtils.mkdir_p(File.join(@file_cache_path, 'snappy')) FileUtils.touch(File.join(@file_cache_path, 'snappy', 'patter')) end it "should return the relative paths" do Chef::FileCache.list.sort.should == %w{snappy/patter whiz/bang} end it "searches for cached files by globbing" do Chef::FileCache.find('snappy/**/*').should == %w{snappy/patter} end end describe "when checking for the existence of a file" do before do FileUtils.mkdir_p(File.join(@file_cache_path, 'whiz')) end it "has a key if the corresponding cache file exists" do FileUtils.touch(File.join(@file_cache_path, 'whiz', 'bang')) Chef::FileCache.should have_key("whiz/bang") end it "doesn't have a key if the corresponding cache file doesn't exist" do Chef::FileCache.should_not have_key("whiz/bang") end end end chef-11.8.2/spec/unit/user_spec.rb0000644000004100000410000001641512254362222016775 0ustar www-datawww-data# # Author:: Steven Danna (steve@opscode.com) # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/user' require 'tempfile' describe Chef::User do before(:each) do @user = Chef::User.new end describe "initialize" do it "should be a Chef::User" do @user.should be_a_kind_of(Chef::User) end end describe "name" do it "should let you set the name to a string" do @user.name("ops_master").should == "ops_master" end it "should return the current name" do @user.name "ops_master" @user.name.should == "ops_master" end # It is not feasible to check all invalid characters. Here are a few # that we probably care about. it "should not accept invalid characters" do # capital letters lambda { @user.name "Bar" }.should raise_error(ArgumentError) # slashes lambda { @user.name "foo/bar" }.should raise_error(ArgumentError) # ? lambda { @user.name "foo?" }.should raise_error(ArgumentError) # & lambda { @user.name "foo&" }.should raise_error(ArgumentError) end it "should not accept spaces" do lambda { @user.name "ops master" }.should raise_error(ArgumentError) end it "should throw an ArgumentError if you feed it anything but a string" do lambda { @user.name Hash.new }.should raise_error(ArgumentError) end end describe "admin" do it "should let you set the admin bit" do @user.admin(true).should == true end it "should return the current admin value" do @user.admin true @user.admin.should == true end it "should default to false" do @user.admin.should == false end it "should throw an ArgumentError if you feed it anything but true or false" do lambda { @user.name Hash.new }.should raise_error(ArgumentError) end end describe "public_key" do it "should let you set the public key" do @user.public_key("super public").should == "super public" end it "should return the current public key" do @user.public_key("super public") @user.public_key.should == "super public" end it "should throw an ArgumentError if you feed it something lame" do lambda { @user.public_key Hash.new }.should raise_error(ArgumentError) end end describe "private_key" do it "should let you set the private key" do @user.private_key("super private").should == "super private" end it "should return the private key" do @user.private_key("super private") @user.private_key.should == "super private" end it "should throw an ArgumentError if you feed it something lame" do lambda { @user.private_key Hash.new }.should raise_error(ArgumentError) end end describe "when serializing to JSON" do before(:each) do @user.name("black") @user.public_key("crowes") @json = @user.to_json end it "serializes as a JSON object" do @json.should match(/^\{.+\}$/) end it "includes the name value" do @json.should include(%q{"name":"black"}) end it "includes the public key value" do @json.should include(%{"public_key":"crowes"}) end it "includes the 'admin' flag" do @json.should include(%q{"admin":false}) end it "includes the private key when present" do @user.private_key("monkeypants") @user.to_json.should include(%q{"private_key":"monkeypants"}) end it "does not include the private key if not present" do @json.should_not include("private_key") end it "includes the password if present" do @user.password "password" @user.to_json.should include(%q{"password":"password"}) end it "does not include the password if not present" do @json.should_not include("password") end end describe "when deserializing from JSON" do before(:each) do user = { "name" => "mr_spinks", "public_key" => "turtles", "private_key" => "pandas", "password" => "password", "admin" => true } @user = Chef::User.from_json(user.to_json) end it "should deserialize to a Chef::User object" do @user.should be_a_kind_of(Chef::User) end it "preserves the name" do @user.name.should == "mr_spinks" end it "preserves the public key" do @user.public_key.should == "turtles" end it "preserves the admin status" do @user.admin.should be_true end it "includes the private key if present" do @user.private_key.should == "pandas" end it "includes the password if present" do @user.password.should == "password" end end describe "API Interactions" do before (:each) do @user = Chef::User.new @user.name "foobar" @http_client = mock("Chef::REST mock") Chef::REST.stub!(:new).and_return(@http_client) end describe "list" do before(:each) do Chef::Config[:chef_server_url] = "http://www.example.com" @osc_response = { "admin" => "http://www.example.com/users/admin"} @ohc_response = [ { "user" => { "username" => "admin" }} ] end it "lists all clients on an OSC server" do @http_client.stub!(:get_rest).with("users").and_return(@osc_response) Chef::User.list.should == @osc_response end it "lists all clients on an OHC/OPC server" do @http_client.stub!(:get_rest).with("users").and_return(@ohc_response) # We expect that Chef::User.list will give a consistent response # so OHC API responses should be transformed to OSC-style output. Chef::User.list.should == @osc_response end end describe "create" do it "creates a new user via the API" do @user.password "password" @http_client.should_receive(:post_rest).with("users", {:name => "foobar", :admin => false, :password => "password"}).and_return({}) @user.create end end describe "read" do it "loads a named user from the API" do @http_client.should_receive(:get_rest).with("users/foobar").and_return({"name" => "foobar", "admin" => true, "public_key" => "pubkey"}) user = Chef::User.load("foobar") user.name.should == "foobar" user.admin.should == true user.public_key.should == "pubkey" end end describe "update" do it "updates an existing user on via the API" do @http_client.should_receive(:put_rest).with("users/foobar", {:name => "foobar", :admin => false}).and_return({}) @user.update end end describe "destroy" do it "deletes the specified user via the API" do @http_client.should_receive(:delete_rest).with("users/foobar") @user.destroy end end end end chef-11.8.2/spec/unit/recipe_spec.rb0000644000004100000410000002156012254362222017263 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Walters () # Author:: Tim Hinderliter () # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2008-2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Recipe do before(:each) do @cookbook_repo = File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "cookbooks")) cl = Chef::CookbookLoader.new(@cookbook_repo) cl.load_cookbooks @cookbook_collection = Chef::CookbookCollection.new(cl) @node = Chef::Node.new @node.normal[:tags] = Array.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) @recipe = Chef::Recipe.new("hjk", "test", @run_context) # Shell/ext.rb is on the run path, and it defines # Chef::Recipe#resources to call pp, which we don't want when # we're running tests. @recipe.stub!(:pp) end describe "method_missing" do describe "resources" do it "should load a two word (zen_master) resource" do lambda do @recipe.zen_master "monkey" do peace true end end.should_not raise_error(ArgumentError) end it "should load a one word (cat) resource" do lambda do @recipe.cat "loulou" do pretty_kitty true end end.should_not raise_error(ArgumentError) end it "should load a four word (one_two_three_four) resource" do lambda do @recipe.one_two_three_four "numbers" do i_can_count true end end.should_not raise_error(ArgumentError) end it "should throw an error if you access a resource that we can't find" do lambda { @recipe.not_home("not_home_resource") }.should raise_error(NameError) end it "should require a name argument" do lambda { @recipe.cat }.should raise_error(ArgumentError, "You must supply a name when declaring a cat resource") end it "should allow regular errors (not NameErrors) to pass unchanged" do lambda { @recipe.cat("felix") { raise ArgumentError, "You Suck" } }.should raise_error(ArgumentError) end it "should add our zen_master to the collection" do @recipe.zen_master "monkey" do peace true end @run_context.resource_collection.lookup("zen_master[monkey]").name.should eql("monkey") end it "should add our zen masters to the collection in the order they appear" do %w{monkey dog cat}.each do |name| @recipe.zen_master name do peace true end end @run_context.resource_collection.map{|r| r.name}.should eql(["monkey", "dog", "cat"]) end it "should return the new resource after creating it" do res = @recipe.zen_master "makoto" do peace true end res.resource_name.should eql(:zen_master) res.name.should eql("makoto") end describe "should locate platform mapped resources" do it "locate resource for particular platform" do Object.const_set('ShaunTheSheep', Class.new(Chef::Resource){ provides :laughter, :on_platforms => ["television"] }) @node.automatic[:platform] = "television" @node.automatic[:platform_version] = "123" res = @recipe.laughter "timmy" res.name.should eql("timmy") res.kind_of?(ShaunTheSheep) end it "locate a resource for all platforms" do Object.const_set("YourMom", Class.new(Chef::Resource){ provides :love_and_caring }) res = @recipe.love_and_caring "mommy" res.name.should eql("mommy") res.kind_of?(YourMom) end end end describe "resource definitions" do it "should execute defined resources" do crow_define = Chef::ResourceDefinition.new crow_define.define :crow, :peace => false, :something => true do zen_master "lao tzu" do peace params[:peace] something params[:something] end end @run_context.definitions[:crow] = crow_define @recipe.crow "mine" do peace true end @run_context.resource_collection.resources(:zen_master => "lao tzu").name.should eql("lao tzu") @run_context.resource_collection.resources(:zen_master => "lao tzu").something.should eql(true) end it "should set the node on defined resources" do crow_define = Chef::ResourceDefinition.new crow_define.define :crow, :peace => false, :something => true do zen_master "lao tzu" do peace params[:peace] something params[:something] end end @run_context.definitions[:crow] = crow_define @node.normal[:foo] = false @recipe.crow "mine" do something node[:foo] end @recipe.resources(:zen_master => "lao tzu").something.should eql(false) end end end describe "instance_eval" do it "should handle an instance_eval properly" do code = <<-CODE zen_master "gnome" do peace = true end CODE lambda { @recipe.instance_eval(code) }.should_not raise_error @recipe.resources(:zen_master => "gnome").name.should eql("gnome") end end describe "from_file" do it "should load a resource from a ruby file" do @recipe.from_file(File.join(CHEF_SPEC_DATA, "recipes", "test.rb")) res = @recipe.resources(:file => "/etc/nsswitch.conf") res.name.should eql("/etc/nsswitch.conf") res.action.should eql([:create]) res.owner.should eql("root") res.group.should eql("root") res.mode.should eql(0644) end it "should raise an exception if the file cannot be found or read" do lambda { @recipe.from_file("/tmp/monkeydiving") }.should raise_error(IOError) end end describe "include_recipe" do it "should evaluate another recipe with include_recipe" do @run_context.include_recipe "openldap::gigantor" res = @run_context.resource_collection.resources(:cat => "blanket") res.name.should eql("blanket") res.pretty_kitty.should eql(false) end it "should load the default recipe for a cookbook if include_recipe is called without a ::" do @run_context.include_recipe "openldap" res = @run_context.resource_collection.resources(:cat => "blanket") res.name.should eql("blanket") res.pretty_kitty.should eql(true) end it "should store that it has seen a recipe in the run_context" do @run_context.include_recipe "openldap" @run_context.loaded_recipe?("openldap").should be_true end it "should not include the same recipe twice" do @cookbook_collection[:openldap].should_receive(:load_recipe).with("default", @run_context) @recipe.include_recipe "openldap" @cookbook_collection[:openldap].should_not_receive(:load_recipe).with("default", @run_context) @recipe.include_recipe "openldap" end end describe "tags" do it "should set tags via tag" do @recipe.tag "foo" @node[:tags].should include("foo") end it "should set multiple tags via tag" do @recipe.tag "foo", "bar" @node[:tags].should include("foo") @node[:tags].should include("bar") end it "should not set the same tag twice via tag" do @recipe.tag "foo" @recipe.tag "foo" @node[:tags].should eql([ "foo" ]) end it "should return the current list of tags from tag with no arguments" do @recipe.tag "foo" @recipe.tag.should eql([ "foo" ]) end it "should return true from tagged? if node is tagged" do @recipe.tag "foo" @recipe.tagged?("foo").should be(true) end it "should return false from tagged? if node is not tagged" do @recipe.tagged?("foo").should be(false) end it "should return false from tagged? if node is not tagged" do @recipe.tagged?("foo").should be(false) end it "should remove a tag from the tag list via untag" do @recipe.tag "foo" @recipe.untag "foo" @node[:tags].should eql([]) end it "should remove multiple tags from the tag list via untag" do @recipe.tag "foo", "bar" @recipe.untag "bar", "foo" @node[:tags].should eql([]) end end end chef-11.8.2/spec/unit/registry_helper_spec.rb0000644000004100000410000004553412254362222021232 0ustar www-datawww-data# # Author:: Prajakta Purohit (prajakta@opscode.com) # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::RegistryKey do let(:value1) { { :name => "one", :type => :string, :data => "1" } } let(:key_path) { 'HKCU\Software\OpscodeNumbers' } let(:key) { 'Software\OpscodeNumbers' } let(:key_parent) { 'Software' } let(:key_to_delete) { 'OpscodeNumbers' } let(:sub_key) {'OpscodePrimes'} let(:missing_key_path) {'HKCU\Software'} before(:each) do Chef::Win32::Registry.any_instance.stub(:machine_architecture).and_return(:x86_64) @registry = Chef::Win32::Registry.new() #Making the values for registry constants available on unix Object.send(:remove_const, 'Win32') if defined?(Win32) Win32 = Module.new Win32::Registry = Class.new Win32::Registry::KEY_SET_VALUE = 0x0002 Win32::Registry::KEY_QUERY_VALUE = 0x0001 Win32::Registry::KEY_WRITE = 0x00020000 | 0x0002 | 0x0004 Win32::Registry::KEY_READ = 0x00020000 | 0x0001 | 0x0008 | 0x0010 Win32::Registry::Error = Class.new(RuntimeError) @hive_mock = mock("::Win32::Registry::HKEY_CURRENT_USER") @reg_mock = mock("reg") end describe "get_values" do it "gets all values for a key if the key exists" do @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @registry.should_receive(:key_exists!).with(key_path).and_return(true) @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) @reg_mock.should_receive(:map) @registry.get_values(key_path) end it "throws an exception if key does not exist" do @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @registry.should_receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing) lambda{@registry.get_values(key_path)}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end end describe "set_value" do it "does nothing if key and hive and value exist" do @registry.should_receive(:key_exists!).with(key_path).and_return(true) @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @registry.should_receive(:value_exists?).with(key_path, value1).and_return(true) @registry.should_receive(:data_exists?).with(key_path, value1).and_return(true) @registry.set_value(key_path, value1) end it "updates value if key and hive and value exist, but data is different" do @registry.should_receive(:key_exists!).with(key_path).and_return(true) @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @registry.should_receive(:value_exists?).with(key_path, value1).and_return(true) @registry.should_receive(:data_exists?).with(key_path, value1).and_return(false) @hive_mock.should_receive(:open).with(key, Win32::Registry::KEY_SET_VALUE | ::Win32::Registry::KEY_QUERY_VALUE | @registry.registry_system_architecture).and_yield(@reg_mock) @registry.should_receive(:get_type_from_name).with(:string).and_return(1) @reg_mock.should_receive(:write).with("one", 1, "1") @registry.set_value(key_path, value1) end it "creates value if the key exists and the value does not exist" do @registry.should_receive(:key_exists!).with(key_path).and_return(true) @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @registry.should_receive(:value_exists?).with(key_path, value1).and_return(false) @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_SET_VALUE | ::Win32::Registry::KEY_QUERY_VALUE | @registry.registry_system_architecture).and_yield(@reg_mock) @registry.should_receive(:get_type_from_name).with(:string).and_return(1) @reg_mock.should_receive(:write).with("one", 1, "1") @registry.set_value(key_path, value1) end it "should raise an exception if the key does not exist" do @registry.should_receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing) lambda {@registry.set_value(key_path, value1)}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end end describe "delete_value" do it "deletes value if value exists" do @registry.should_receive(:value_exists?).with(key_path, value1).and_return(true) @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_SET_VALUE | @registry.registry_system_architecture).and_yield(@reg_mock) @reg_mock.should_receive(:delete_value).with("one").and_return(true) @registry.delete_value(key_path, value1) end it "raises an exception if the key does not exist" do @registry.should_receive(:value_exists?).with(key_path, value1).and_return(true) @registry.should_receive(:get_hive_and_key).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing) @registry.delete_value(key_path, value1) end it "does nothing if the value does not exist" do @registry.should_receive(:value_exists?).with(key_path, value1).and_return(false) @registry.delete_value(key_path, value1) end end describe "create_key" do it "creates key if intermediate keys are missing and recursive is set to true" do @registry.should_receive(:keys_missing?).with(key_path).and_return(true) @registry.should_receive(:create_missing).with(key_path) @registry.should_receive(:key_exists?).with(key_path).and_return(false) @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @hive_mock.should_receive(:create).with(key, ::Win32::Registry::KEY_WRITE | @registry.registry_system_architecture) @registry.create_key(key_path, true) end it "raises an exception if intermediate keys are missing and recursive is set to false" do @registry.should_receive(:keys_missing?).with(key_path).and_return(true) lambda{@registry.create_key(key_path, false)}.should raise_error(Chef::Exceptions::Win32RegNoRecursive) end it "does nothing if the key exists" do @registry.should_receive(:keys_missing?).with(key_path).and_return(true) @registry.should_receive(:create_missing).with(key_path) @registry.should_receive(:key_exists?).with(key_path).and_return(true) @registry.create_key(key_path, true) end it "create key if intermediate keys not missing and recursive is set to false" do @registry.should_receive(:keys_missing?).with(key_path).and_return(false) @registry.should_receive(:key_exists?).with(key_path).and_return(false) @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @hive_mock.should_receive(:create).with(key, ::Win32::Registry::KEY_WRITE | @registry.registry_system_architecture) @registry.create_key(key_path, false) end it "create key if intermediate keys not missing and recursive is set to true" do @registry.should_receive(:keys_missing?).with(key_path).and_return(false) @registry.should_receive(:key_exists?).with(key_path).and_return(false) @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @hive_mock.should_receive(:create).with(key, ::Win32::Registry::KEY_WRITE | @registry.registry_system_architecture) @registry.create_key(key_path, true) end end describe "delete_key", :windows_only do it "deletes key if it has subkeys and recursive is set to true" do @registry.should_receive(:key_exists?).with(key_path).and_return(true) @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @registry.should_receive(:has_subkeys?).with(key_path).and_return(true) @registry.should_receive(:get_subkeys).with(key_path).and_return([sub_key]) @registry.should_receive(:key_exists?).with(key_path+"\\"+sub_key).and_return(true) @registry.should_receive(:get_hive_and_key).with(key_path+"\\"+sub_key).and_return([@hive_mock, key+"\\"+sub_key]) @registry.should_receive(:has_subkeys?).with(key_path+"\\"+sub_key).and_return(false) @registry.should_receive(:delete_key_ex).twice @registry.delete_key(key_path, true) end it "raises an exception if it has subkeys but recursive is set to false" do @registry.should_receive(:key_exists?).with(key_path).and_return(true) @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @registry.should_receive(:has_subkeys?).with(key_path).and_return(true) lambda{@registry.delete_key(key_path, false)}.should raise_error(Chef::Exceptions::Win32RegNoRecursive) end it "deletes key if the key exists and has no subkeys" do @registry.should_receive(:key_exists?).with(key_path).and_return(true) @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @registry.should_receive(:has_subkeys?).with(key_path).and_return(false) @registry.should_receive(:delete_key_ex) @registry.delete_key(key_path, true) end end describe "key_exists?" do it "returns true if key_exists" do @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) @registry.key_exists?(key_path).should == true end it "returns false if key does not exist" do @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_raise(::Win32::Registry::Error) @registry.key_exists?(key_path).should == false end end describe "key_exists!" do it "throws an exception if the key_parent does not exist" do @registry.should_receive(:key_exists?).with(key_path).and_return(false) lambda{@registry.key_exists!(key_path)}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end end describe "hive_exists?" do it "returns true if the hive exists" do @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @registry.hive_exists?(key_path) == true end it "returns false if the hive does not exist" do @registry.should_receive(:get_hive_and_key).with(key_path).and_raise(Chef::Exceptions::Win32RegHiveMissing) @registry.hive_exists?(key_path) == false end end describe "has_subkeys?" do it "returns true if the key has subkeys" do @registry.should_receive(:key_exists!).with(key_path).and_return(true) @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) @reg_mock.should_receive(:each_key).and_yield(key) @registry.has_subkeys?(key_path) == true end it "returns false if the key does not have subkeys" do @registry.should_receive(:key_exists!).with(key_path).and_return(true) @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) @reg_mock.should_receive(:each_key).and_return(no_args()) @registry.has_subkeys?(key_path).should == false end it "throws an exception if the key does not exist" do @registry.should_receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing) lambda {@registry.set_value(key_path, value1)}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end end describe "get_subkeys" do it "returns the subkeys if they exist" do @registry.should_receive(:key_exists!).with(key_path).and_return(true) @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) @reg_mock.should_receive(:each_key).and_yield(sub_key) @registry.get_subkeys(key_path) end end describe "value_exists?" do it "throws an exception if the key does not exist" do @registry.should_receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing) lambda {@registry.value_exists?(key_path, value1)}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end it "returns true if the value exists" do @registry.should_receive(:key_exists!).with(key_path).and_return(true) @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) @reg_mock.should_receive(:any?).and_yield("one") @registry.value_exists?(key_path, value1) == true end it "returns false if the value does not exist" do @registry.should_receive(:key_exists!).with(key_path).and_return(true) @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) @reg_mock.should_receive(:any?).and_yield(no_args()) @registry.value_exists?(key_path, value1) == false end end describe "data_exists?" do it "throws an exception if the key does not exist" do @registry.should_receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing) lambda {@registry.data_exists?(key_path, value1)}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end it "returns true if the data exists" do @registry.should_receive(:key_exists!).with(key_path).and_return(true) @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @registry.should_receive(:get_type_from_name).with(:string).and_return(1) @reg_mock.should_receive(:each).with(no_args()).and_yield("one", 1, "1") @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) @registry.data_exists?(key_path, value1).should == true end it "returns false if the data does not exist" do @registry.should_receive(:key_exists!).with(key_path).and_return(true) @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) @registry.should_receive(:get_type_from_name).with(:string).and_return(1) @reg_mock.should_receive(:each).with(no_args()).and_yield("one", 1, "2") @registry.data_exists?(key_path, value1).should == false end end describe "value_exists!" do it "does nothing if the value exists" do @registry.should_receive(:value_exists?).with(key_path, value1).and_return(true) @registry.value_exists!(key_path, value1) end it "throws an exception if the value does not exist" do @registry.should_receive(:value_exists?).with(key_path, value1).and_return(false) lambda{@registry.value_exists!(key_path, value1)}.should raise_error(Chef::Exceptions::Win32RegValueMissing) end end describe "data_exists!" do it "does nothing if the data exists" do @registry.should_receive(:data_exists?).with(key_path, value1).and_return(true) @registry.data_exists!(key_path, value1) end it "throws an exception if the data does not exist" do @registry.should_receive(:data_exists?).with(key_path, value1).and_return(false) lambda{@registry.data_exists!(key_path, value1)}.should raise_error(Chef::Exceptions::Win32RegDataMissing) end end describe "type_matches?" do it "returns true if type matches" do @registry.should_receive(:value_exists!).with(key_path, value1).and_return(true) @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) @registry.should_receive(:get_type_from_name).with(:string).and_return(1) @reg_mock.should_receive(:each).and_yield("one", 1) @registry.type_matches?(key_path, value1).should == true end it "returns false if type does not match" do @registry.should_receive(:value_exists!).with(key_path, value1).and_return(true) @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) @reg_mock.should_receive(:each).and_yield("two", 2) @registry.type_matches?(key_path, value1).should == false end it "throws an exception if value does not exist" do @registry.should_receive(:value_exists?).with(key_path, value1).and_return(false) lambda{@registry.type_matches?(key_path, value1)}.should raise_error(Chef::Exceptions::Win32RegValueMissing) end end describe "type_matches!" do it "does nothing if the type_matches" do @registry.should_receive(:type_matches?).with(key_path, value1).and_return(true) @registry.type_matches!(key_path, value1) end it "throws an exception if the type does not match" do @registry.should_receive(:type_matches?).with(key_path, value1).and_return(false) lambda{@registry.type_matches!(key_path, value1)}.should raise_error(Chef::Exceptions::Win32RegTypesMismatch) end end describe "keys_missing?" do it "returns true if the keys are missing" do @registry.should_receive(:key_exists?).with(missing_key_path).and_return(false) @registry.keys_missing?(key_path).should == true end it "returns false if no keys in the path are missing" do @registry.should_receive(:key_exists?).with(missing_key_path).and_return(true) @registry.keys_missing?(key_path).should == false end end end chef-11.8.2/spec/unit/resource_collection_spec.rb0000644000004100000410000002106312254362222022054 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Walters () # Copyright:: Copyright (c) 2008, 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::ResourceCollection do before(:each) do @rc = Chef::ResourceCollection.new() @resource = Chef::Resource::ZenMaster.new("makoto") end describe "initialize" do it "should return a Chef::ResourceCollection" do @rc.should be_kind_of(Chef::ResourceCollection) end end describe "[]" do it "should accept Chef::Resources through [index]" do lambda { @rc[0] = @resource }.should_not raise_error lambda { @rc[0] = "string" }.should raise_error end it "should allow you to fetch Chef::Resources by position" do @rc[0] = @resource @rc[0].should eql(@resource) end end describe "push" do it "should accept Chef::Resources through pushing" do lambda { @rc.push(@resource) }.should_not raise_error lambda { @rc.push("string") }.should raise_error end end describe "<<" do it "should accept the << operator" do lambda { @rc << @resource }.should_not raise_error end end describe "insert" do it "should accept only Chef::Resources" do lambda { @rc.insert(@resource) }.should_not raise_error lambda { @rc.insert("string") }.should raise_error end it "should append resources to the end of the collection when not executing a run" do zmr = Chef::Resource::ZenMaster.new("there is no spoon") @rc.insert(@resource) @rc.insert(zmr) @rc[0].should eql(@resource) @rc[1].should eql(zmr) end it "should insert resources to the middle of the collection if called while executing a run" do resource_to_inject = Chef::Resource::ZenMaster.new("there is no spoon") zmr = Chef::Resource::ZenMaster.new("morpheus") dummy = Chef::Resource::ZenMaster.new("keanu reeves") @rc.insert(zmr) @rc.insert(dummy) @rc.execute_each_resource do |resource| @rc.insert(resource_to_inject) if resource == zmr end @rc[0].should eql(zmr) @rc[1].should eql(resource_to_inject) @rc[2].should eql(dummy) end end describe "each" do it "should allow you to iterate over every resource in the collection" do load_up_resources results = Array.new lambda { @rc.each do |r| results << r.name end }.should_not raise_error results.each_index do |i| case i when 0 results[i].should eql("dog") when 1 results[i].should eql("cat") when 2 results[i].should eql("monkey") end end end end describe "each_index" do it "should allow you to iterate over every resource by index" do load_up_resources results = Array.new lambda { @rc.each_index do |i| results << @rc[i].name end }.should_not raise_error() results.each_index do |i| case i when 0 results[i].should eql("dog") when 1 results[i].should eql("cat") when 2 results[i].should eql("monkey") end end end end describe "lookup" do it "should allow you to find resources by name via lookup" do zmr = Chef::Resource::ZenMaster.new("dog") @rc << zmr @rc.lookup(zmr.to_s).should eql(zmr) zmr = Chef::Resource::ZenMaster.new("cat") @rc[0] = zmr @rc.lookup(zmr).should eql(zmr) zmr = Chef::Resource::ZenMaster.new("monkey") @rc.push(zmr) @rc.lookup(zmr).should eql(zmr) end it "should raise an exception if you send something strange to lookup" do lambda { @rc.lookup(:symbol) }.should raise_error(ArgumentError) end it "should raise an exception if it cannot find a resource with lookup" do lambda { @rc.lookup("zen_master[dog]") }.should raise_error(Chef::Exceptions::ResourceNotFound) end end describe "resources" do it "should find a resource by symbol and name (:zen_master => monkey)" do load_up_resources @rc.resources(:zen_master => "monkey").name.should eql("monkey") end it "should find a resource by symbol and array of names (:zen_master => [a,b])" do load_up_resources results = @rc.resources(:zen_master => [ "monkey", "dog" ]) results.length.should eql(2) check_by_names(results, "monkey", "dog") end it "should find resources of multiple kinds (:zen_master => a, :file => b)" do load_up_resources results = @rc.resources(:zen_master => "monkey", :file => "something") results.length.should eql(2) check_by_names(results, "monkey", "something") end it "should find a resource by string zen_master[a]" do load_up_resources @rc.resources("zen_master[monkey]").name.should eql("monkey") end it "should find resources by strings of zen_master[a,b]" do load_up_resources results = @rc.resources("zen_master[monkey,dog]") results.length.should eql(2) check_by_names(results, "monkey", "dog") end it "should find resources of multiple types by strings of zen_master[a]" do load_up_resources results = @rc.resources("zen_master[monkey]", "file[something]") results.length.should eql(2) check_by_names(results, "monkey", "something") end it "should raise an exception if you pass a bad name to resources" do lambda { @rc.resources("michael jackson") }.should raise_error(ArgumentError) end it "should raise an exception if you pass something other than a string or hash to resource" do lambda { @rc.resources([Array.new]) }.should raise_error(ArgumentError) end it "raises an error when attempting to find a resource that does not exist" do lambda {@rc.find("script[nonesuch]")}.should raise_error(Chef::Exceptions::ResourceNotFound) end end describe "when validating a resource query object" do it "accepts a string of the form 'resource_type[resource_name]'" do @rc.validate_lookup_spec!("resource_type[resource_name]").should be_true end it "accepts a single-element :resource_type => 'resource_name' Hash" do @rc.validate_lookup_spec!(:service => "apache2").should be_true end it "accepts a chef resource object" do res = Chef::Resource.new("foo", nil) @rc.validate_lookup_spec!(res).should be_true end it "rejects a malformed query string" do lambda do @rc.validate_lookup_spec!("resource_type[missing-end-bracket") end.should raise_error(Chef::Exceptions::InvalidResourceSpecification) end it "rejects an argument that is not a String, Hash, or Chef::Resource" do lambda do @rc.validate_lookup_spec!(Object.new) end.should raise_error(Chef::Exceptions::InvalidResourceSpecification) end end describe "to_json" do it "should serialize to json" do json = @rc.to_json json.should =~ /json_class/ json.should =~ /instance_vars/ end end describe "self.from_json" do it "should deserialize itself from json" do @rc << @resource json = @rc.to_json s_rc = Chef::JSONCompat.from_json(json) s_rc.should be_a_kind_of(Chef::ResourceCollection) s_rc[0].name.should eql(@resource.name) end end describe "provides access to the raw resources array" do it "returns the resources via the all_resources method" do @rc.all_resources.should equal(@rc.instance_variable_get(:@resources)) end end describe "provides access to stepable iterator" do it "returns the iterator object" do @rc.instance_variable_set(:@iterator, :fooboar) @rc.iterator.should == :fooboar end end def check_by_names(results, *names) names.each do |res_name| results.detect{ |res| res.name == res_name }.should_not eql(nil) end end def load_up_resources %w{dog cat monkey}.each do |n| @rc << Chef::Resource::ZenMaster.new(n) end @rc << Chef::Resource::File.new("something") end end chef-11.8.2/spec/unit/resource_definition_spec.rb0000644000004100000410000000645512254362222022061 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::ResourceDefinition do before(:each) do @def = Chef::ResourceDefinition.new() end describe "initialize" do it "should be a Chef::ResourceDefinition" do @def.should be_a_kind_of(Chef::ResourceDefinition) end it "should not initialize a new node if one is not provided" do @def.node.should eql(nil) end it "should accept a node as an argument" do node = Chef::Node.new node.name("bobo") @def = Chef::ResourceDefinition.new(node) @def.node.name.should == "bobo" end end describe "node" do it "should set the node with node=" do node = Chef::Node.new node.name("bobo") @def.node = node @def.node.name.should == "bobo" end it "should return the node" do @def.node = Chef::Node.new @def.node.should be_a_kind_of(Chef::Node) end end it "should accept a new definition with a symbol for a name" do lambda { @def.define :smoke do end }.should_not raise_error(ArgumentError) lambda { @def.define "george washington" do end }.should raise_error(ArgumentError) @def.name.should eql(:smoke) end it "should accept a new definition with a hash" do lambda { @def.define :smoke, :cigar => "cuban", :cigarette => "marlboro" do end }.should_not raise_error(ArgumentError) end it "should expose the prototype hash params in the params hash" do @def.define :smoke, :cigar => "cuban", :cigarette => "marlboro" do; end @def.params[:cigar].should eql("cuban") @def.params[:cigarette].should eql("marlboro") end it "should store the block passed to define as a proc under recipe" do @def.define :smoke do "I am what I am" end @def.recipe.should be_a_kind_of(Proc) @def.recipe.call.should eql("I am what I am") end it "should set paramaters based on method_missing" do @def.mind "to fly" @def.params[:mind].should eql("to fly") end it "should raise an exception if prototype_params is not a hash" do lambda { @def.define :monkey, Array.new do end }.should raise_error(ArgumentError) end it "should raise an exception if define is called without a block" do lambda { @def.define :monkey }.should raise_error(ArgumentError) end it "should load a description from a file" do @def.from_file(File.join(CHEF_SPEC_DATA, "definitions", "test.rb")) @def.name.should eql(:rico_suave) @def.params[:rich].should eql("smooth") end it "should turn itself into a string based on the name with to_s" do @def.name = :woot @def.to_s.should eql("woot") end end chef-11.8.2/spec/unit/version_constraint_spec.rb0000644000004100000410000001013112254362222021735 0ustar www-datawww-data# # Author:: Seth Falcon () # Copyright:: Copyright 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'spec_helper' require 'chef/version_constraint' describe Chef::VersionConstraint do describe "validation" do bad_version = ["> >", ">= 1.2.z", "> 1.2.3 < 5.0", "> 1.2.3, < 5.0"] bad_op = ["<3.0.1", ">$ 1.2.3", "! 3.4"] o_error = Chef::Exceptions::InvalidVersionConstraint v_error = Chef::Exceptions::InvalidCookbookVersion bad_version.each do |s| it "should raise #{v_error} when given #{s}" do lambda { Chef::VersionConstraint.new s }.should raise_error(v_error) end end bad_op.each do |s| it "should raise #{o_error} when given #{s}" do lambda { Chef::VersionConstraint.new s }.should raise_error(o_error) end end it "should interpret a lone version number as implicit = OP" do vc = Chef::VersionConstraint.new("1.2.3") vc.to_s.should == "= 1.2.3" end it "should allow initialization with [] for back compatibility" do Chef::VersionConstraint.new([]) == Chef::VersionConstraint.new end it "should allow initialization with ['1.2.3'] for back compatibility" do Chef::VersionConstraint.new(["1.2"]) == Chef::VersionConstraint.new("1.2") end end it "should default to >= 0.0.0" do vc = Chef::VersionConstraint.new vc.to_s.should == ">= 0.0.0" end it "should default to >= 0.0.0 when initialized with nil" do Chef::VersionConstraint.new(nil).to_s.should == ">= 0.0.0" end it "should work with Chef::Version classes" do vc = Chef::VersionConstraint.new("1.0") vc.version.should be_an_instance_of(Chef::Version) end describe "include?" do describe "handles various input data types" do before do @vc = Chef::VersionConstraint.new "> 1.2.3" end it "String" do @vc.should include "1.4" end it "Chef::Version" do @vc.should include Chef::Version.new("1.4") end it "Chef::CookbookVersion" do cv = Chef::CookbookVersion.new("alice") cv.version = "1.4" @vc.should include cv end end it "strictly less than" do vc = Chef::VersionConstraint.new "< 1.2.3" vc.should_not include "1.3.0" vc.should_not include "1.2.3" vc.should include "1.2.2" end it "strictly greater than" do vc = Chef::VersionConstraint.new "> 1.2.3" vc.should include "1.3.0" vc.should_not include "1.2.3" vc.should_not include "1.2.2" end it "less than or equal to" do vc = Chef::VersionConstraint.new "<= 1.2.3" vc.should_not include "1.3.0" vc.should include "1.2.3" vc.should include "1.2.2" end it "greater than or equal to" do vc = Chef::VersionConstraint.new ">= 1.2.3" vc.should include "1.3.0" vc.should include "1.2.3" vc.should_not include "1.2.2" end it "equal to" do vc = Chef::VersionConstraint.new "= 1.2.3" vc.should_not include "1.3.0" vc.should include "1.2.3" vc.should_not include "0.3.0" end it "pessimistic ~> x.y.z" do vc = Chef::VersionConstraint.new "~> 1.2.3" vc.should include "1.2.3" vc.should include "1.2.4" vc.should_not include "1.2.2" vc.should_not include "1.3.0" vc.should_not include "2.0.0" end it "pessimistic ~> x.y" do vc = Chef::VersionConstraint.new "~> 1.2" vc.should include "1.3.3" vc.should include "1.4" vc.should_not include "2.2" vc.should_not include "0.3.0" end end end chef-11.8.2/spec/unit/cookbook_manifest_spec.rb0000644000004100000410000005440512254362222021514 0ustar www-datawww-data# # Author:: Tim Hinderliter () # Author:: Christopher Walters () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe "Chef::CookbookVersion manifest" do before(:each) do @cookbook = Chef::CookbookVersion.new "test-cookbook" @cookbook.manifest = { "files" => [ # afile.rb { :name => "afile.rb", :path => "files/host-examplehost.example.org/afile.rb", :checksum => "csum-host", :specificity => "host-examplehost.example.org" }, { :name => "afile.rb", :path => "files/ubuntu-9.10/afile.rb", :checksum => "csum-platver-full", :specificity => "ubuntu-9.10" }, { :name => "afile.rb", :path => "files/newubuntu-9/afile.rb", :checksum => "csum-platver-partial", :specificity => "newubuntu-9" }, { :name => "afile.rb", :path => "files/ubuntu/afile.rb", :checksum => "csum-plat", :specificity => "ubuntu" }, { :name => "afile.rb", :path => "files/default/afile.rb", :checksum => "csum-default", :specificity => "default" }, # for different/odd platform_versions { :name => "bfile.rb", :path => "files/fakeos-2.0.rc.1/bfile.rb", :checksum => "csum2-platver-full", :specificity => "fakeos-2.0.rc.1" }, { :name => "bfile.rb", :path => "files/newfakeos-2.0.rc/bfile.rb", :checksum => "csum2-platver-partial", :specificity => "newfakeos-2.0.rc" }, { :name => "bfile.rb", :path => "files/fakeos-maple tree/bfile.rb", :checksum => "csum3-platver-full", :specificity => "maple tree" }, { :name => "bfile.rb", :path => "files/fakeos-1/bfile.rb", :checksum => "csum4-platver-full", :specificity => "fakeos-1" }, # directory adirectory { :name => "anotherfile1.rb", :path => "files/host-examplehost.example.org/adirectory/anotherfile1.rb.host", :checksum => "csum-host-1", :specificity => "host-examplehost.example.org" }, { :name => "anotherfile2.rb", :path => "files/host-examplehost.example.org/adirectory/anotherfile2.rb.host", :checksum => "csum-host-2", :specificity => "host-examplehost.example.org" }, { :name => "anotherfile1.rb", :path => "files/ubuntu-9.10/adirectory/anotherfile1.rb.platform-full-version", :checksum => "csum-platver-full-1", :specificity => "ubuntu-9.10" }, { :name => "anotherfile2.rb", :path => "files/ubuntu-9.10/adirectory/anotherfile2.rb.platform-full-version", :checksum => "csum-platver-full-2", :specificity => "ubuntu-9.10" }, { :name => "anotherfile1.rb", :path => "files/newubuntu-9/adirectory/anotherfile1.rb.platform-partial-version", :checksum => "csum-platver-partial-1", :specificity => "newubuntu-9" }, { :name => "anotherfile2.rb", :path => "files/newubuntu-9/adirectory/anotherfile2.rb.platform-partial-version", :checksum => "csum-platver-partial-2", :specificity => "nweubuntu-9" }, { :name => "anotherfile1.rb", :path => "files/ubuntu/adirectory/anotherfile1.rb.platform", :checksum => "csum-plat-1", :specificity => "ubuntu" }, { :name => "anotherfile2.rb", :path => "files/ubuntu/adirectory/anotherfile2.rb.platform", :checksum => "csum-plat-2", :specificity => "ubuntu" }, { :name => "anotherfile1.rb", :path => "files/default/adirectory/anotherfile1.rb.default", :checksum => "csum-default-1", :specificity => "default" }, { :name => "anotherfile2.rb", :path => "files/default/adirectory/anotherfile2.rb.default", :checksum => "csum-default-2", :specificity => "default" }, # for different/odd platform_versions { :name => "anotherfile1.rb", :path => "files/fakeos-2.0.rc.1/adirectory/anotherfile1.rb.platform-full-version", :checksum => "csum2-platver-full-1", :specificity => "fakeos-2.0.rc.1" }, { :name => "anotherfile2.rb", :path => "files/fakeos-2.0.rc.1/adirectory/anotherfile2.rb.platform-full-version", :checksum => "csum2-platver-full-2", :specificity => "fakeos-2.0.rc.1" }, { :name => "anotherfile1.rb", :path => "files/newfakeos-2.0.rc.1/adirectory/anotherfile1.rb.platform-partial-version", :checksum => "csum2-platver-partial-1", :specificity => "newfakeos-2.0.rc" }, { :name => "anotherfile2.rb", :path => "files/newfakeos-2.0.rc.1/adirectory/anotherfile2.rb.platform-partial-version", :checksum => "csum2-platver-partial-2", :specificity => "newfakeos-2.0.rc" }, { :name => "anotherfile1.rb", :path => "files/fakeos-maple tree/adirectory/anotherfile1.rb.platform-full-version", :checksum => "csum3-platver-full-1", :specificity => "fakeos-maple tree" }, { :name => "anotherfile2.rb", :path => "files/fakeos-maple tree/adirectory/anotherfile2.rb.platform-full-version", :checksum => "csum3-platver-full-2", :specificity => "fakeos-maple tree" }, { :name => "anotherfile1.rb", :path => "files/fakeos-1/adirectory/anotherfile1.rb.platform-full-version", :checksum => "csum4-platver-full-1", :specificity => "fakeos-1" }, { :name => "anotherfile2.rb", :path => "files/fakeos-1/adirectory/anotherfile2.rb.platform-full-version", :checksum => "csum4-platver-full-2", :specificity => "fakeos-1" }, ] } end it "should return a manifest record based on priority preference: host" do node = Chef::Node.new node.automatic_attrs[:platform] = "ubuntu" node.automatic_attrs[:platform_version] = "9.10" node.automatic_attrs[:fqdn] = "examplehost.example.org" manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") manifest_record.should_not be_nil manifest_record[:checksum].should == "csum-host" end it "should return a manifest record based on priority preference: platform & full version" do node = Chef::Node.new node.automatic_attrs[:platform] = "ubuntu" node.automatic_attrs[:platform_version] = "9.10" node.automatic_attrs[:fqdn] = "differenthost.example.org" manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") manifest_record.should_not be_nil manifest_record[:checksum].should == "csum-platver-full" end it "should return a manifest record based on priority preference: platform & partial version" do node = Chef::Node.new node.automatic_attrs[:platform] = "newubuntu" node.automatic_attrs[:platform_version] = "9.10" node.automatic_attrs[:fqdn] = "differenthost.example.org" manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") manifest_record.should_not be_nil manifest_record[:checksum].should == "csum-platver-partial" end it "should return a manifest record based on priority preference: platform only" do node = Chef::Node.new node.automatic_attrs[:platform] = "ubuntu" node.automatic_attrs[:platform_version] = "1.0" node.automatic_attrs[:fqdn] = "differenthost.example.org" manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") manifest_record.should_not be_nil manifest_record[:checksum].should == "csum-plat" end it "should return a manifest record based on priority preference: default" do node = Chef::Node.new node.automatic_attrs[:platform] = "notubuntu" node.automatic_attrs[:platform_version] = "1.0" node.automatic_attrs[:fqdn] = "differenthost.example.org" manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") manifest_record.should_not be_nil manifest_record[:checksum].should == "csum-default" end it "should return a manifest record based on priority preference: platform & full version - platform_version variant 1" do node = Chef::Node.new node.automatic_attrs[:platform] = "fakeos" node.automatic_attrs[:platform_version] = "2.0.rc.1" node.automatic_attrs[:fqdn] = "differenthost.example.org" manifest_record = @cookbook.preferred_manifest_record(node, :files, "bfile.rb") manifest_record.should_not be_nil manifest_record[:checksum].should == "csum2-platver-full" end it "should return a manifest record based on priority preference: platform & partial version - platform_version variant 1" do node = Chef::Node.new node.automatic_attrs[:platform] = "newfakeos" node.automatic_attrs[:platform_version] = "2.0.rc.1" node.automatic_attrs[:fqdn] = "differenthost.example.org" manifest_record = @cookbook.preferred_manifest_record(node, :files, "bfile.rb") manifest_record.should_not be_nil manifest_record[:checksum].should == "csum2-platver-partial" end it "should return a manifest record based on priority preference: platform & full version - platform_version variant 2" do node = Chef::Node.new node.automatic_attrs[:platform] = "fakeos" node.automatic_attrs[:platform_version] = "maple tree" node.automatic_attrs[:fqdn] = "differenthost.example.org" manifest_record = @cookbook.preferred_manifest_record(node, :files, "bfile.rb") manifest_record.should_not be_nil manifest_record[:checksum].should == "csum3-platver-full" end it "should return a manifest record based on priority preference: platform & full version - platform_version variant 3" do node = Chef::Node.new node.automatic_attrs[:platform] = "fakeos" node.automatic_attrs[:platform_version] = "1" node.automatic_attrs[:fqdn] = "differenthost.example.org" manifest_record = @cookbook.preferred_manifest_record(node, :files, "bfile.rb") manifest_record.should_not be_nil manifest_record[:checksum].should == "csum4-platver-full" end describe "when fetching the contents of a directory by file specificity" do it "should return a directory of manifest records based on priority preference: host" do node = Chef::Node.new node.automatic_attrs[:platform] = "ubuntu" node.automatic_attrs[:platform_version] = "9.10" node.automatic_attrs[:fqdn] = "examplehost.example.org" manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") manifest_records.should_not be_nil manifest_records.size.should == 2 checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } checksums.sort.should == ["csum-host-1", "csum-host-2"] end it "should return a directory of manifest records based on priority preference: platform & full version" do node = Chef::Node.new node.automatic_attrs[:platform] = "ubuntu" node.automatic_attrs[:platform_version] = "9.10" node.automatic_attrs[:fqdn] = "differenthost.example.org" manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") manifest_records.should_not be_nil manifest_records.size.should == 2 checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } checksums.sort.should == ["csum-platver-full-1", "csum-platver-full-2"] end it "should return a directory of manifest records based on priority preference: platform & partial version" do node = Chef::Node.new node.automatic_attrs[:platform] = "newubuntu" node.automatic_attrs[:platform_version] = "9.10" node.automatic_attrs[:fqdn] = "differenthost.example.org" manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") manifest_records.should_not be_nil manifest_records.size.should == 2 checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } checksums.sort.should == ["csum-platver-partial-1", "csum-platver-partial-2"] end it "should return a directory of manifest records based on priority preference: platform only" do node = Chef::Node.new node.automatic_attrs[:platform] = "ubuntu" node.automatic_attrs[:platform_version] = "1.0" node.automatic_attrs[:fqdn] = "differenthost.example.org" manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") manifest_records.should_not be_nil manifest_records.size.should == 2 checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } checksums.sort.should == ["csum-plat-1", "csum-plat-2"] end it "should return a directory of manifest records based on priority preference: default" do node = Chef::Node.new node.automatic_attrs[:platform] = "notubuntu" node.automatic_attrs[:platform_version] = "1.0" node.automatic_attrs[:fqdn] = "differenthost.example.org" manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") manifest_records.should_not be_nil manifest_records.size.should == 2 checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } checksums.sort.should == ["csum-default-1", "csum-default-2"] end it "should return a manifest record based on priority preference: platform & full version - platform_version variant 1" do node = Chef::Node.new node.automatic_attrs[:platform] = "fakeos" node.automatic_attrs[:platform_version] = "2.0.rc.1" node.automatic_attrs[:fqdn] = "differenthost.example.org" manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") manifest_records.should_not be_nil manifest_records.size.should == 2 checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } checksums.sort.should == ["csum2-platver-full-1", "csum2-platver-full-2"] end it "should return a manifest record based on priority preference: platform & partial version - platform_version variant 1" do node = Chef::Node.new node.automatic_attrs[:platform] = "newfakeos" node.automatic_attrs[:platform_version] = "2.0.rc.1" node.automatic_attrs[:fqdn] = "differenthost.example.org" manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") manifest_records.should_not be_nil manifest_records.size.should == 2 checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } checksums.sort.should == ["csum2-platver-partial-1", "csum2-platver-partial-2"] end it "should return a manifest record based on priority preference: platform & full version - platform_version variant 2" do node = Chef::Node.new node.automatic_attrs[:platform] = "fakeos" node.automatic_attrs[:platform_version] = "maple tree" node.automatic_attrs[:fqdn] = "differenthost.example.org" manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") manifest_records.should_not be_nil manifest_records.size.should == 2 checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } checksums.sort.should == ["csum3-platver-full-1", "csum3-platver-full-2"] end it "should return a manifest record based on priority preference: platform & full version - platform_version variant 3" do node = Chef::Node.new node.automatic_attrs[:platform] = "fakeos" node.automatic_attrs[:platform_version] = "1" node.automatic_attrs[:fqdn] = "differenthost.example.org" manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") manifest_records.should_not be_nil manifest_records.size.should == 2 checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } checksums.sort.should == ["csum4-platver-full-1", "csum4-platver-full-2"] end end ## Globbing the relative paths out of the manifest records ## describe "when globbing for relative file paths based on filespecificity" do it "should return a list of relative paths based on priority preference: host" do node = Chef::Node.new node.automatic_attrs[:platform] = "ubuntu" node.automatic_attrs[:platform_version] = "9.10" node.automatic_attrs[:fqdn] = "examplehost.example.org" filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") filenames.should_not be_nil filenames.size.should == 2 filenames.sort.should == ['anotherfile1.rb.host', 'anotherfile2.rb.host'] end it "should return a list of relative paths based on priority preference: platform & full version" do node = Chef::Node.new node.automatic_attrs[:platform] = "ubuntu" node.automatic_attrs[:platform_version] = "9.10" node.automatic_attrs[:fqdn] = "differenthost.example.org" filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") filenames.should_not be_nil filenames.size.should == 2 filenames.sort.should == ['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version'] end it "should return a list of relative paths based on priority preference: platform & partial version" do node = Chef::Node.new node.automatic_attrs[:platform] = "newubuntu" node.automatic_attrs[:platform_version] = "9.10" node.automatic_attrs[:fqdn] = "differenthost.example.org" filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") filenames.should_not be_nil filenames.size.should == 2 filenames.sort.should == ['anotherfile1.rb.platform-partial-version', 'anotherfile2.rb.platform-partial-version'] end it "should return a list of relative paths based on priority preference: platform only" do node = Chef::Node.new node.automatic_attrs[:platform] = "ubuntu" node.automatic_attrs[:platform_version] = "1.0" node.automatic_attrs[:fqdn] = "differenthost.example.org" filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") filenames.should_not be_nil filenames.size.should == 2 filenames.sort.should == ['anotherfile1.rb.platform', 'anotherfile2.rb.platform'] end it "should return a list of relative paths based on priority preference: default" do node = Chef::Node.new node.automatic_attrs[:platform] = "notubuntu" node.automatic_attrs[:platform_version] = "1.0" node.automatic_attrs[:fqdn] = "differenthost.example.org" filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") filenames.should_not be_nil filenames.size.should == 2 filenames.sort.should == ['anotherfile1.rb.default', 'anotherfile2.rb.default'] end it "should return a list of relative paths based on priority preference: platform & full version - platform_version variant 1" do node = Chef::Node.new node.automatic_attrs[:platform] = "fakeos" node.automatic_attrs[:platform_version] = "2.0.rc.1" node.automatic_attrs[:fqdn] = "differenthost.example.org" filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") filenames.should_not be_nil filenames.size.should == 2 filenames.sort.should == ['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version'] end it "should return a list of relative paths based on priority preference: platform & partial version - platform_version variant 1" do node = Chef::Node.new node.automatic_attrs[:platform] = "newfakeos" node.automatic_attrs[:platform_version] = "2.0.rc.1" node.automatic_attrs[:fqdn] = "differenthost.example.org" filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") filenames.should_not be_nil filenames.size.should == 2 filenames.sort.should == ['anotherfile1.rb.platform-partial-version', 'anotherfile2.rb.platform-partial-version'] end it "should return a list of relative paths based on priority preference: platform & full version - platform_version variant 2" do node = Chef::Node.new node.automatic_attrs[:platform] = "fakeos" node.automatic_attrs[:platform_version] = "maple tree" node.automatic_attrs[:fqdn] = "differenthost.example.org" filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") filenames.should_not be_nil filenames.size.should == 2 filenames.sort.should == ['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version'] end it "should return a list of relative paths based on priority preference: platform & full version - platform_version variant 3" do node = Chef::Node.new node.automatic_attrs[:platform] = "fakeos" node.automatic_attrs[:platform_version] = "1" node.automatic_attrs[:fqdn] = "differenthost.example.org" filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") filenames.should_not be_nil filenames.size.should == 2 filenames.sort.should == ['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version'] end end end chef-11.8.2/spec/unit/resource_platform_map_spec.rb0000644000004100000410000001174212254362222022405 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::PlatformMap do before(:each) do @platform_map = Chef::Resource::PlatformMap.new({ :windows => { "6.1" => { :file => "softiefile", :else => "thing" }, :default => { :file => Chef::Resource::File, :ping => "pong", :cat => "nice" } }, :pop_tron => { }, :default => { :soundwave => "lazerbeak", :directory => Chef::Resource::Directory, } }) end describe 'filtering the map' do it "returns resources for platform and version" do pmap = @platform_map.filter("Windows", "6.1") pmap.should be_a_kind_of(Hash) pmap[:file].should eql("softiefile") end it "returns platform default resources if version does not exist" do pmap = @platform_map.filter("windows", "1") pmap.should be_a_kind_of(Hash) pmap[:file].should eql(Chef::Resource::File) end it "returns global default resources if none exist for plaform" do pmap = @platform_map.filter("pop_tron", "1") pmap.should be_a_kind_of(Hash) pmap[:directory].should eql(Chef::Resource::Directory) end it "returns global default resources if platform does not exist" do pmap = @platform_map.filter("BeOS", "1") pmap.should be_a_kind_of(Hash) pmap[:soundwave].should eql("lazerbeak") end it "returns a merged map of platform version and plaform default resources" do pmap = @platform_map.filter("Windows", "6.1") pmap[:file].should eql("softiefile") pmap[:ping].should eql("pong") end it "returns a merged map of platform specific version and global defaults" do pmap = @platform_map.filter("Windows", "6.1") pmap[:file].should eql("softiefile") pmap[:soundwave].should eql("lazerbeak") end end describe 'finding a resource' do it "returns a resource for a platform directly by short name" do @platform_map.get(:file, "windows", "6.1").should eql("softiefile") end it "returns a default resource if platform and version don't exist" do @platform_map.get(:remote_file).should eql(Chef::Resource::RemoteFile) end it "raises an exception if a resource cannot be found" do lambda { @platform_map.get(:coffee, "windows", "6.1")}.should raise_error(NameError) end it "returns a resource with a Chef::Resource object" do kitty = Chef::Resource::Cat.new("loulou") @platform_map.get(kitty, "windows", "6.1").should eql("nice") end end describe 'building the map' do it "allows passing of a resource map at creation time" do @new_map = Chef::Resource::PlatformMap.new({:the_dude => {:default => 'abides'}}) @new_map.map[:the_dude][:default].should eql("abides") end it "defaults to a resource map with :default key" do @new_map = Chef::Resource::PlatformMap.new @new_map.map.has_key?(:default) end it "updates the resource map with a map" do @platform_map.set( :platform => :darwin, :version => "9.2.2", :short_name => :file, :resource => "masterful" ) @platform_map.map[:darwin]["9.2.2"][:file].should eql("masterful") @platform_map.set( :platform => :darwin, :short_name => :file, :resource => "masterful" ) @platform_map.map[:darwin][:default][:file].should eql("masterful") @platform_map.set( :short_name => :file, :resource => "masterful" ) @platform_map.map[:default][:file].should eql("masterful") @platform_map.set( :platform => :hero, :version => "9.2.2", :short_name => :file, :resource => "masterful" ) @platform_map.map[:hero]["9.2.2"][:file].should eql("masterful") @platform_map.set( :short_name => :file, :resource => "masterful" ) @platform_map.map[:default][:file].should eql("masterful") @platform_map.set( :short_name => :file, :resource => "masterful" ) @platform_map.map[:default][:file].should eql("masterful") @platform_map.set( :platform => :neurosis, :short_name => :package, :resource => "masterful" ) @platform_map.map[:neurosis][:default][:package].should eql("masterful") end end end chef-11.8.2/spec/unit/api_client_spec.rb0000644000004100000410000001733412254362222020127 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/api_client' require 'tempfile' describe Chef::ApiClient do before(:each) do @client = Chef::ApiClient.new end it "has a name attribute" do @client.name("ops_master") @client.name.should == "ops_master" end it "does not allow spaces in the name" do lambda { @client.name "ops master" }.should raise_error(ArgumentError) end it "only allows string values for the name" do lambda { @client.name Hash.new }.should raise_error(ArgumentError) end it "has an admin flag attribute" do @client.admin(true) @client.admin.should be_true end it "defaults to non-admin" do @client.admin.should be_false end it "allows only boolean values for the admin flag" do lambda { @client.admin(false) }.should_not raise_error lambda { @client.admin(Hash.new) }.should raise_error(ArgumentError) end it "has a 'validator' flag attribute" do @client.validator(true) @client.validator.should be_true end it "defaults to non-validator" do @client.validator.should be_false end it "allows only boolean values for the 'validator' flag" do lambda { @client.validator(false) }.should_not raise_error lambda { @client.validator(Hash.new) }.should raise_error(ArgumentError) end it "has a public key attribute" do @client.public_key("super public") @client.public_key.should == "super public" end it "accepts only String values for the public key" do lambda { @client.public_key "" }.should_not raise_error lambda { @client.public_key Hash.new }.should raise_error(ArgumentError) end it "has a private key attribute" do @client.private_key("super private") @client.private_key.should == "super private" end it "accepts only String values for the private key" do lambda { @client.private_key "" }.should_not raise_error lambda { @client.private_key Hash.new }.should raise_error(ArgumentError) end describe "when serializing to JSON" do before(:each) do @client.name("black") @client.public_key("crowes") @json = @client.to_json end it "serializes as a JSON object" do @json.should match(/^\{.+\}$/) end it "includes the name value" do @json.should include(%q{"name":"black"}) end it "includes the public key value" do @json.should include(%{"public_key":"crowes"}) end it "includes the 'admin' flag" do @json.should include(%q{"admin":false}) end it "includes the 'validator' flag" do @json.should include(%q{"validator":false}) end it "includes the private key when present" do @client.private_key("monkeypants") @client.to_json.should include(%q{"private_key":"monkeypants"}) end it "does not include the private key if not present" do @json.should_not include("private_key") end end describe "when deserializing from JSON" do before(:each) do client = { "name" => "black", "public_key" => "crowes", "private_key" => "monkeypants", "admin" => true, "validator" => true, "json_class" => "Chef::ApiClient" } @client = Chef::JSONCompat.from_json(client.to_json) end it "should deserialize to a Chef::ApiClient object" do @client.should be_a_kind_of(Chef::ApiClient) end it "preserves the name" do @client.name.should == "black" end it "preserves the public key" do @client.public_key.should == "crowes" end it "preserves the admin status" do @client.admin.should be_true end it "preserves the 'validator' status" do @client.validator.should be_true end it "includes the private key if present" do @client.private_key.should == "monkeypants" end end describe "with correctly configured API credentials" do before do Chef::Config[:node_name] = "silent-bob" Chef::Config[:client_key] = File.expand_path('ssl/private_key.pem', CHEF_SPEC_DATA) end after do Chef::Config[:node_name] = nil Chef::Config[:client_key] = nil end let :private_key_data do File.open(Chef::Config[:client_key], "r") {|f| f.read.chomp } end it "has an HTTP client configured with default credentials" do @client.http_api.should be_a_kind_of(Chef::REST) @client.http_api.client_name.should == "silent-bob" @client.http_api.signing_key.to_s.should == private_key_data end end describe "when requesting a new key" do before do @http_client = mock("Chef::REST mock") Chef::REST.stub!(:new).and_return(@http_client) end context "and the client does not exist on the server" do before do @a_404_response = Net::HTTPNotFound.new("404 not found and such", nil, nil) @a_404_exception = Net::HTTPServerException.new("404 not found exception", @a_404_response) @http_client.should_receive(:get).with("clients/lost-my-key").and_raise(@a_404_exception) end it "raises a 404 error" do lambda { Chef::ApiClient.reregister("lost-my-key") }.should raise_error(Net::HTTPServerException) end end context "and the client exists" do before do @api_client_without_key = Chef::ApiClient.new @api_client_without_key.name("lost-my-key") @http_client.should_receive(:get).with("clients/lost-my-key").and_return(@api_client_without_key) end context "and the client exists on a Chef 11-like server" do before do @api_client_with_key = Chef::ApiClient.new @api_client_with_key.name("lost-my-key") @api_client_with_key.private_key("the new private key") @http_client.should_receive(:put). with("clients/lost-my-key", :name => "lost-my-key", :admin => false, :validator => false, :private_key => true). and_return(@api_client_with_key) end it "returns an ApiClient with a private key" do response = Chef::ApiClient.reregister("lost-my-key") # no sane == method for ApiClient :'( response.should == @api_client_without_key response.private_key.should == "the new private key" response.name.should == "lost-my-key" response.admin.should be_false end end context "and the client exists on a Chef 10-like server" do before do @api_client_with_key = {"name" => "lost-my-key", "private_key" => "the new private key"} @http_client.should_receive(:put). with("clients/lost-my-key", :name => "lost-my-key", :admin => false, :validator => false, :private_key => true). and_return(@api_client_with_key) end it "returns an ApiClient with a private key" do response = Chef::ApiClient.reregister("lost-my-key") # no sane == method for ApiClient :'( response.should == @api_client_without_key response.private_key.should == "the new private key" response.name.should == "lost-my-key" response.admin.should be_false response.validator.should be_false end end end end end chef-11.8.2/spec/unit/runner_spec.rb0000644000004100000410000003340612254362222017327 0ustar www-datawww-data # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' class SnitchyProvider < Chef::Provider def self.all_actions_called @all_actions_called ||= [] end def self.action_called(action) all_actions_called << action end def self.clear_action_record @all_actions_called = nil end def load_current_resource true end def action_first_action @new_resource.updated_by_last_action(true) self.class.action_called(:first) end def action_second_action @new_resource.updated_by_last_action(true) self.class.action_called(:second) end def action_third_action @new_resource.updated_by_last_action(true) self.class.action_called(:third) end end class FailureResource < Chef::Resource attr_accessor :action def initialize(*args) super @action = :fail end def provider FailureProvider end end class FailureProvider < Chef::Provider class ChefClientFail < StandardError; end def load_current_resource true end def action_fail raise ChefClientFail, "chef had an error of some sort" end end describe Chef::Runner do before(:each) do @node = Chef::Node.new @node.name "latte" @node.automatic[:platform] = "mac_os_x" @node.automatic[:platform_version] = "10.5.1" @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, Chef::CookbookCollection.new({}), @events) @first_resource = Chef::Resource::Cat.new("loulou1", @run_context) @run_context.resource_collection << @first_resource Chef::Platform.set( :resource => :cat, :provider => Chef::Provider::SnakeOil ) @runner = Chef::Runner.new(@run_context) end it "should pass each resource in the collection to a provider" do @run_context.resource_collection.should_receive(:execute_each_resource).once @runner.converge end it "should use the provider specified by the resource (if it has one)" do provider = Chef::Provider::Easy.new(@run_context.resource_collection[0], @run_context) # Expect provider to be called twice, because will fall back to old provider lookup @run_context.resource_collection[0].should_receive(:provider).twice.and_return(Chef::Provider::Easy) Chef::Provider::Easy.should_receive(:new).once.and_return(provider) @runner.converge end it "should use the platform provider if it has one" do Chef::Platform.should_receive(:find_provider_for_node).once.and_return(Chef::Provider::SnakeOil) @runner.converge end it "should run the action for each resource" do Chef::Platform.should_receive(:find_provider_for_node).once.and_return(Chef::Provider::SnakeOil) provider = Chef::Provider::SnakeOil.new(@run_context.resource_collection[0], @run_context) provider.should_receive(:action_sell).once.and_return(true) Chef::Provider::SnakeOil.should_receive(:new).once.and_return(provider) @runner.converge end it "should raise exceptions as thrown by a provider" do provider = Chef::Provider::SnakeOil.new(@run_context.resource_collection[0], @run_context) Chef::Provider::SnakeOil.stub!(:new).once.and_return(provider) provider.stub!(:action_sell).once.and_raise(ArgumentError) lambda { @runner.converge }.should raise_error(ArgumentError) end it "should not raise exceptions thrown by providers if the resource has ignore_failure set to true" do @run_context.resource_collection[0].stub!(:ignore_failure).and_return(true) provider = Chef::Provider::SnakeOil.new(@run_context.resource_collection[0], @run_context) Chef::Provider::SnakeOil.stub!(:new).once.and_return(provider) provider.stub!(:action_sell).once.and_raise(ArgumentError) lambda { @runner.converge }.should_not raise_error(ArgumentError) end it "should retry with the specified delay if retries are specified" do @first_resource.retries 3 provider = Chef::Provider::SnakeOil.new(@run_context.resource_collection[0], @run_context) Chef::Provider::SnakeOil.stub!(:new).once.and_return(provider) provider.stub!(:action_sell).and_raise(ArgumentError) @first_resource.should_receive(:sleep).with(2).exactly(3).times lambda { @runner.converge }.should raise_error(ArgumentError) end it "should execute immediate actions on changed resources" do notifying_resource = Chef::Resource::Cat.new("peanut", @run_context) notifying_resource.action = :purr # only action that will set updated on the resource @run_context.resource_collection << notifying_resource @first_resource.action = :nothing # won't be updated unless notified by other resource notifying_resource.notifies(:purr, @first_resource, :immediately) @runner.converge @first_resource.should be_updated end it "should follow a chain of actions" do @first_resource.action = :nothing middle_resource = Chef::Resource::Cat.new("peanut", @run_context) middle_resource.action = :nothing @run_context.resource_collection << middle_resource middle_resource.notifies(:purr, @first_resource, :immediately) last_resource = Chef::Resource::Cat.new("snuffles", @run_context) last_resource.action = :purr @run_context.resource_collection << last_resource last_resource.notifies(:purr, middle_resource, :immediately) @runner.converge last_resource.should be_updated # by action(:purr) middle_resource.should be_updated # by notification from last_resource @first_resource.should be_updated # by notification from middle_resource end it "should execute delayed actions on changed resources" do @first_resource.action = :nothing second_resource = Chef::Resource::Cat.new("peanut", @run_context) second_resource.action = :purr @run_context.resource_collection << second_resource second_resource.notifies(:purr, @first_resource, :delayed) @runner.converge @first_resource.should be_updated end it "should execute delayed notifications when a failure occurs in the chef client run" do @first_resource.action = :nothing second_resource = Chef::Resource::Cat.new("peanut", @run_context) second_resource.action = :purr @run_context.resource_collection << second_resource second_resource.notifies(:purr, @first_resource, :delayed) third_resource = FailureResource.new("explode", @run_context) @run_context.resource_collection << third_resource lambda {@runner.converge}.should raise_error(FailureProvider::ChefClientFail) @first_resource.should be_updated end it "should execute delayed notifications when a failure occurs in a notification" do @first_resource.action = :nothing second_resource = Chef::Resource::Cat.new("peanut", @run_context) second_resource.action = :purr @run_context.resource_collection << second_resource third_resource = FailureResource.new("explode", @run_context) third_resource.action = :nothing @run_context.resource_collection << third_resource second_resource.notifies(:fail, third_resource, :delayed) second_resource.notifies(:purr, @first_resource, :delayed) lambda {@runner.converge}.should raise_error(FailureProvider::ChefClientFail) @first_resource.should be_updated end it "should execute delayed notifications when a failure occurs in multiple notifications" do @first_resource.action = :nothing second_resource = Chef::Resource::Cat.new("peanut", @run_context) second_resource.action = :purr @run_context.resource_collection << second_resource third_resource = FailureResource.new("explode", @run_context) third_resource.action = :nothing @run_context.resource_collection << third_resource fourth_resource = FailureResource.new("explode again", @run_context) fourth_resource.action = :nothing @run_context.resource_collection << fourth_resource second_resource.notifies(:fail, third_resource, :delayed) second_resource.notifies(:fail, fourth_resource, :delayed) second_resource.notifies(:purr, @first_resource, :delayed) exception = nil begin @runner.converge rescue => e exception = e end exception.should be_a(Chef::Exceptions::MultipleFailures) expected_message =<<-E Multiple failures occurred: * FailureProvider::ChefClientFail occurred in delayed notification: [explode] (dynamically defined) had an error: FailureProvider::ChefClientFail: chef had an error of some sort * FailureProvider::ChefClientFail occurred in delayed notification: [explode again] (dynamically defined) had an error: FailureProvider::ChefClientFail: chef had an error of some sort E exception.message.should == expected_message @first_resource.should be_updated end it "does not duplicate delayed notifications" do SnitchyProvider.clear_action_record Chef::Platform.set( :resource => :cat, :provider => SnitchyProvider ) @first_resource.action = :nothing second_resource = Chef::Resource::Cat.new("peanut", @run_context) second_resource.action = :first_action @run_context.resource_collection << second_resource third_resource = Chef::Resource::Cat.new("snickers", @run_context) third_resource.action = :first_action @run_context.resource_collection << third_resource second_resource.notifies(:second_action, @first_resource, :delayed) second_resource.notifies(:third_action, @first_resource, :delayed) third_resource.notifies(:second_action, @first_resource, :delayed) third_resource.notifies(:third_action, @first_resource, :delayed) @runner.converge # resources 2 and 3 call :first_action in the course of normal resource # execution, and schedule delayed actions :second and :third on the first # resource. The duplicate actions should "collapse" to a single notification # and order should be preserved. SnitchyProvider.all_actions_called.should == [:first, :first, :second, :third] end it "executes delayed notifications in the order they were declared" do SnitchyProvider.clear_action_record Chef::Platform.set( :resource => :cat, :provider => SnitchyProvider ) @first_resource.action = :nothing second_resource = Chef::Resource::Cat.new("peanut", @run_context) second_resource.action = :first_action @run_context.resource_collection << second_resource third_resource = Chef::Resource::Cat.new("snickers", @run_context) third_resource.action = :first_action @run_context.resource_collection << third_resource second_resource.notifies(:second_action, @first_resource, :delayed) second_resource.notifies(:second_action, @first_resource, :delayed) third_resource.notifies(:third_action, @first_resource, :delayed) third_resource.notifies(:third_action, @first_resource, :delayed) @runner.converge SnitchyProvider.all_actions_called.should == [:first, :first, :second, :third] end it "does not fire notifications if the resource was not updated by the last action executed" do # REGRESSION TEST FOR CHEF-1452 SnitchyProvider.clear_action_record Chef::Platform.set( :resource => :cat, :provider => SnitchyProvider ) @first_resource.action = :first_action second_resource = Chef::Resource::Cat.new("peanut", @run_context) second_resource.action = :nothing @run_context.resource_collection << second_resource third_resource = Chef::Resource::Cat.new("snickers", @run_context) third_resource.action = :nothing @run_context.resource_collection << third_resource @first_resource.notifies(:second_action, second_resource, :immediately) second_resource.notifies(:third_action, third_resource, :immediately) @runner.converge # All of the resources should only fire once: SnitchyProvider.all_actions_called.should == [:first, :second, :third] # all of the resources should be marked as updated for reporting purposes @first_resource.should be_updated second_resource.should be_updated third_resource.should be_updated end it "should check a resource's only_if and not_if if notified by another resource" do @first_resource.action = :buy only_if_called_times = 0 @first_resource.only_if {only_if_called_times += 1; true} not_if_called_times = 0 @first_resource.not_if {not_if_called_times += 1; false} second_resource = Chef::Resource::Cat.new("carmel", @run_context) @run_context.resource_collection << second_resource second_resource.notifies(:purr, @first_resource, :delayed) second_resource.action = :purr # hits only_if first time when the resource is run in order, second on notify @runner.converge only_if_called_times.should == 2 not_if_called_times.should == 2 end it "should resolve resource references in notifications when resources are defined lazily" do @first_resource.action = :nothing lazy_resources = lambda { last_resource = Chef::Resource::Cat.new("peanut", @run_context) @run_context.resource_collection << last_resource last_resource.notifies(:purr, @first_resource.to_s, :delayed) last_resource.action = :purr } second_resource = Chef::Resource::RubyBlock.new("myblock", @run_context) @run_context.resource_collection << second_resource second_resource.block { lazy_resources.call } @runner.converge @first_resource.should be_updated end end chef-11.8.2/spec/unit/provider/0000755000004100000410000000000012254362222016303 5ustar www-datawww-datachef-11.8.2/spec/unit/provider/route_spec.rb0000644000004100000410000002364112254362222021006 0ustar www-datawww-data# # Author:: Bryan McLellan (btm@loftninjas.org) # Copyright:: Copyright (c) 2009 Bryan McLellan # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Route do before do @node = Chef::Node.new @cookbook_collection = Chef::CookbookCollection.new([]) @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) @new_resource = Chef::Resource::Route.new('10.0.0.10') @new_resource.gateway "10.0.0.9" @current_resource = Chef::Resource::Route.new('10.0.0.10') @current_resource.gateway "10.0.0.9" @provider = Chef::Provider::Route.new(@new_resource, @run_context) @provider.current_resource = @current_resource end describe Chef::Provider::Route, "hex2ip" do it "should return nil if ip address is invalid" do @provider.hex2ip('foo').should be_nil # does not even look like an ip @provider.hex2ip('ABCDEFGH').should be_nil # 8 chars, but invalid end it "should return quad-dotted notation for a valid IP" do @provider.hex2ip('01234567').should == '103.69.35.1' @provider.hex2ip('0064a8c0').should == '192.168.100.0' @provider.hex2ip('00FFFFFF').should == '255.255.255.0' end end describe Chef::Provider::Route, "load_current_resource" do context "on linux" do before do @node.automatic_attrs[:os] = 'linux' routing_table = "Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT\n" + "eth0 0064A8C0 0984A8C0 0003 0 0 0 00FFFFFF 0 0 0\n" route_file = StringIO.new(routing_table) File.stub!(:open).with("/proc/net/route", "r").and_return(route_file) end it "should set is_running to false when a route is not detected" do resource = Chef::Resource::Route.new('10.10.10.0/24') resource.stub!(:gateway).and_return("10.0.0.1") resource.stub!(:device).and_return("eth0") provider = Chef::Provider::Route.new(resource, @run_context) provider.load_current_resource provider.is_running.should be_false end it "should detect existing routes and set is_running attribute correctly" do resource = Chef::Resource::Route.new('192.168.100.0/24') resource.stub!(:gateway).and_return("192.168.132.9") resource.stub!(:device).and_return("eth0") provider = Chef::Provider::Route.new(resource, @run_context) provider.load_current_resource provider.is_running.should be_true end it "should use gateway value when matching routes" do resource = Chef::Resource::Route.new('192.168.100.0/24') resource.stub!(:gateway).and_return("10.10.10.10") resource.stub!(:device).and_return("eth0") provider = Chef::Provider::Route.new(resource, @run_context) provider.load_current_resource provider.is_running.should be_false end end end describe Chef::Provider::Route, "action_add" do it "should add the route if it does not exist" do @provider.stub!(:run_command).and_return(true) @current_resource.stub!(:gateway).and_return(nil) @provider.should_receive(:generate_command).once.with(:add) @provider.should_receive(:generate_config) @provider.run_action(:add) @new_resource.should be_updated end it "should not add the route if it exists" do @provider.stub!(:run_command).and_return(true) @provider.stub!(:is_running).and_return(true) @provider.should_not_receive(:generate_command).with(:add) @provider.should_receive(:generate_config) @provider.run_action(:add) @new_resource.should_not be_updated end it "should not delete config file for :add action (CHEF-3332)" do @node.automatic_attrs[:platform] = 'centos' route_file = StringIO.new File.should_receive(:new).and_return(route_file) @resource_add = Chef::Resource::Route.new('192.168.1.0/24 via 192.168.0.1') @run_context.resource_collection << @resource_add @provider.stub!(:run_command).and_return(true) @resource_add.action(:add) @provider.run_action(:add) route_file.string.split("\n").should have(1).items route_file.string.should match(/^192\.168\.1\.0\/24 via 192\.168\.0\.1$/) end end describe Chef::Provider::Route, "action_delete" do it "should delete the route if it exists" do @provider.stub!(:run_command).and_return(true) @provider.should_receive(:generate_command).once.with(:delete) @provider.stub!(:is_running).and_return(true) @provider.run_action(:delete) @new_resource.should be_updated end it "should not delete the route if it does not exist" do @current_resource.stub!(:gateway).and_return(nil) @provider.stub!(:run_command).and_return(true) @provider.should_not_receive(:generate_command).with(:add) @provider.run_action(:delete) @new_resource.should_not be_updated end end describe Chef::Provider::Route, "generate_command for action_add" do it "should include a netmask when a one is specified" do @new_resource.stub!(:netmask).and_return('255.255.0.0') @provider.generate_command(:add).should match(/\/\d{1,2}\s/) end it "should not include a netmask when a one is specified" do @new_resource.stub!(:netmask).and_return(nil) @provider.generate_command(:add).should_not match(/\/\d{1,2}\s/) end it "should include ' via $gateway ' when a gateway is specified" do @provider.generate_command(:add).should match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\s/) end it "should not include ' via $gateway ' when a gateway is not specified" do @new_resource.stub!(:gateway).and_return(nil) @provider.generate_command(:add).should_not match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\s/) end end describe Chef::Provider::Route, "generate_command for action_delete" do it "should include a netmask when a one is specified" do @new_resource.stub!(:netmask).and_return('255.255.0.0') @provider.generate_command(:delete).should match(/\/\d{1,2}\s/) end it "should not include a netmask when a one is specified" do @new_resource.stub!(:netmask).and_return(nil) @provider.generate_command(:delete).should_not match(/\/\d{1,2}\s/) end it "should include ' via $gateway ' when a gateway is specified" do @provider.generate_command(:delete).should match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\s/) end it "should not include ' via $gateway ' when a gateway is not specified" do @new_resource.stub!(:gateway).and_return(nil) @provider.generate_command(:delete).should_not match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\s/) end end describe Chef::Provider::Route, "config_file_contents for action_add" do it "should include a netmask when a one is specified" do @new_resource.stub!(:netmask).and_return('255.255.0.0') @provider.config_file_contents(:add, { :target => @new_resource.target, :netmask => @new_resource.netmask}).should match(/\/\d{1,2}.*\n$/) end it "should not include a netmask when a one is specified" do @provider.config_file_contents(:add, { :target => @new_resource.target}).should_not match(/\/\d{1,2}.*\n$/) end it "should include ' via $gateway ' when a gateway is specified" do @provider.config_file_contents(:add, { :target => @new_resource.target, :gateway => @new_resource.gateway}).should match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\n/) end it "should not include ' via $gateway ' when a gateway is not specified" do @provider.generate_command(:add).should_not match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\n/) end end describe Chef::Provider::Route, "config_file_contents for action_delete" do it "should return an empty string" do @provider.config_file_contents(:delete).should match(/^$/) end end describe Chef::Provider::Route, "generate_config method" do %w[ centos redhat fedora ].each do |platform| it "should write a route file on #{platform} platform" do @node.automatic_attrs[:platform] = platform route_file = StringIO.new File.should_receive(:new).with("/etc/sysconfig/network-scripts/route-eth0", "w").and_return(route_file) #Chef::Log.should_receive(:debug).with("route[10.0.0.10] writing route.eth0\n10.0.0.10 via 10.0.0.9\n") @run_context.resource_collection << @new_resource @provider.generate_config end end it "should put all routes for a device in a route config file" do @node.automatic_attrs[:platform] = 'centos' route_file = StringIO.new File.should_receive(:new).and_return(route_file) @run_context.resource_collection << Chef::Resource::Route.new('192.168.1.0/24 via 192.168.0.1') @run_context.resource_collection << Chef::Resource::Route.new('192.168.2.0/24 via 192.168.0.1') @run_context.resource_collection << Chef::Resource::Route.new('192.168.3.0/24 via 192.168.0.1') @provider.action = :add @provider.generate_config route_file.string.split("\n").should have(3).items route_file.string.should match(/^192\.168\.1\.0\/24 via 192\.168\.0\.1$/) route_file.string.should match(/^192\.168\.2\.0\/24 via 192\.168\.0\.1$/) route_file.string.should match(/^192\.168\.3\.0\/24 via 192\.168\.0\.1$/) end end end chef-11.8.2/spec/unit/provider/git_spec.rb0000644000004100000410000006631512254362222020440 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Git do before(:each) do STDOUT.stub!(:tty?).and_return(true) Chef::Log.level = :info @current_resource = Chef::Resource::Git.new("web2.0 app") @current_resource.revision("d35af14d41ae22b19da05d7d03a0bafc321b244c") @resource = Chef::Resource::Git.new("web2.0 app") @resource.repository "git://github.com/opscode/chef.git" @resource.destination "/my/deploy/dir" @resource.revision "d35af14d41ae22b19da05d7d03a0bafc321b244c" @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @provider = Chef::Provider::Git.new(@resource, @run_context) @provider.current_resource = @current_resource end context "determining the revision of the currently deployed checkout" do before do @stdout = mock("standard out") @stderr = mock("standard error") @exitstatus = mock("exitstatus") end it "sets the current revision to nil if the deploy dir does not exist" do ::File.should_receive(:exist?).with("/my/deploy/dir/.git").and_return(false) @provider.find_current_revision.should be_nil end it "determines the current revision when there is one" do ::File.should_receive(:exist?).with("/my/deploy/dir/.git").and_return(true) @stdout = "9b4d8dc38dd471246e7cfb1c3c1ad14b0f2bee13\n" @provider.should_receive(:shell_out!).with('git rev-parse HEAD', {:cwd => '/my/deploy/dir', :returns => [0,128]}).and_return(mock("ShellOut result", :stdout => @stdout)) @provider.find_current_revision.should eql("9b4d8dc38dd471246e7cfb1c3c1ad14b0f2bee13") end it "gives the current revision as nil when there is no current revision" do ::File.should_receive(:exist?).with("/my/deploy/dir/.git").and_return(true) @stderr = "fatal: Not a git repository (or any of the parent directories): .git" @stdout = "" @provider.should_receive(:shell_out!).with('git rev-parse HEAD', :cwd => '/my/deploy/dir', :returns => [0,128]).and_return(mock("ShellOut result", :stdout => "", :stderr => @stderr)) @provider.find_current_revision.should be_nil end end it "creates a current_resource with the currently deployed revision when a clone exists in the destination dir" do @provider.stub!(:find_current_revision).and_return("681c9802d1c62a45b490786c18f0b8216b309440") @provider.load_current_resource @provider.current_resource.name.should eql(@resource.name) @provider.current_resource.revision.should eql("681c9802d1c62a45b490786c18f0b8216b309440") end it "keeps the node and resource passed to it on initialize" do @provider.node.should equal(@node) @provider.new_resource.should equal(@resource) end context "resolving revisions to a SHA" do before do @git_ls_remote = "git ls-remote \"git://github.com/opscode/chef.git\" " end it "returns resource.revision as is if revision is already a full SHA" do @provider.target_revision.should eql("d35af14d41ae22b19da05d7d03a0bafc321b244c") end it "converts resource.revision from a tag to a SHA" do @resource.revision "v1.0" @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" + "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n") @provider.should_receive(:shell_out!).with(@git_ls_remote + "v1.0*", {:log_tag=>"git[web2.0 app]"}).and_return(mock("ShellOut result", :stdout => @stdout)) @provider.target_revision.should eql("503c22a5e41f5ae3193460cca044ed1435029f53") end it "converts resource.revision from an annotated tag to the tagged SHA (not SHA of tag)" do @resource.revision "v1.0" @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" + "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n" + "663c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0^{}\n") @provider.should_receive(:shell_out!).with(@git_ls_remote + "v1.0*", {:log_tag=>"git[web2.0 app]"}).and_return(mock("ShellOut result", :stdout => @stdout)) @provider.target_revision.should eql("663c22a5e41f5ae3193460cca044ed1435029f53") end it "raises an invalid remote reference error if you try to deploy from ``origin'' and assertions are run" do @resource.revision "origin/" @provider.action = :checkout @provider.define_resource_requirements ::File.stub!(:directory?).with("/my/deploy").and_return(true) lambda {@provider.process_resource_requirements}.should raise_error(Chef::Exceptions::InvalidRemoteGitReference) end it "raises an unresolvable git reference error if the revision can't be resolved to any revision and assertions are run" do @resource.revision "FAIL, that's the revision I want" @provider.action = :checkout @provider.should_receive(:shell_out!).and_return(mock("ShellOut result", :stdout => "\n")) @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::UnresolvableGitReference) end it "does not raise an error if the revision can't be resolved when assertions are not run" do @resource.revision "FAIL, that's the revision I want" @provider.should_receive(:shell_out!).and_return(mock("ShellOut result", :stdout => "\n")) @provider.target_revision.should == nil end it "does not raise an error when the revision is valid and assertions are run." do @resource.revision "0.8-alpha" @stdout = "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" @provider.should_receive(:shell_out!).with(@git_ls_remote + "0.8-alpha*", {:log_tag=>"git[web2.0 app]"}).and_return(mock("ShellOut result", :stdout => @stdout)) @provider.action = :checkout ::File.stub!(:directory?).with("/my/deploy").and_return(true) @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should_not raise_error(RuntimeError) end it "gives the latest HEAD revision SHA if nothing is specified" do @stdout =<<-SHAS 28af684d8460ba4793eda3e7ac238c864a5d029a\tHEAD 503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha 28af684d8460ba4793eda3e7ac238c864a5d029a\trefs/heads/master c44fe79bb5e36941ce799cee6b9de3a2ef89afee\trefs/tags/0.5.2 14534f0e0bf133dc9ff6dbe74f8a0c863ff3ac6d\trefs/tags/0.5.4 d36fddb4291341a1ff2ecc3c560494e398881354\trefs/tags/0.5.6 9e5ce9031cbee81015de680d010b603bce2dd15f\trefs/tags/0.6.0 9b4d8dc38dd471246e7cfb1c3c1ad14b0f2bee13\trefs/tags/0.6.2 014a69af1cdce619de82afaf6cdb4e6ac658fede\trefs/tags/0.7.0 fa8097ff666af3ce64761d8e1f1c2aa292a11378\trefs/tags/0.7.2 44f9be0b33ba5c10027ddb030a5b2f0faa3eeb8d\trefs/tags/0.7.4 d7b9957f67236fa54e660cc3ab45ffecd6e0ba38\trefs/tags/0.7.8 b7d19519a1c15f1c1a324e2683bd728b6198ce5a\trefs/tags/0.7.8^{} ebc1b392fe7e8f0fbabc305c299b4d365d2b4d9b\trefs/tags/chef-server-package SHAS @resource.revision '' @provider.should_receive(:shell_out!).with(@git_ls_remote + "HEAD", {:log_tag=>"git[web2.0 app]"}).and_return(mock("ShellOut result", :stdout => @stdout)) @provider.target_revision.should eql("28af684d8460ba4793eda3e7ac238c864a5d029a") end end it "responds to :revision_slug as an alias for target_revision" do @provider.should respond_to(:revision_slug) end context "with an ssh wrapper" do let(:deploy_user) { "deployNinja" } let(:wrapper) { "do_it_this_way.sh" } let(:expected_cmd) { 'git clone "git://github.com/opscode/chef.git" "/my/deploy/dir"' } let(:default_options) do { :user => deploy_user, :environment => { "GIT_SSH" => wrapper }, :log_tag => "git[web2.0 app]" } end before do @resource.user deploy_user @resource.ssh_wrapper wrapper end context "without a timeout set" do it "clones a repo with default git options" do @provider.should_receive(:shell_out!).with(expected_cmd, default_options) @provider.clone end end context "with a timeout set" do let (:seconds) { 10 } before { @resource.timeout(seconds) } it "clones a repo with amended git options" do @provider.should_receive(:shell_out!).with(expected_cmd, default_options.merge(:timeout => seconds)) @provider.clone end end end it "runs a clone command with escaped destination" do @resource.user "deployNinja" @resource.destination "/Application Support/with/space" @resource.ssh_wrapper "do_it_this_way.sh" expected_cmd = "git clone \"git://github.com/opscode/chef.git\" \"/Application Support/with/space\"" @provider.should_receive(:shell_out!).with(expected_cmd, :user => "deployNinja", :environment =>{"GIT_SSH"=>"do_it_this_way.sh"}, :log_tag => "git[web2.0 app]") @provider.clone end it "compiles a clone command using --depth for shallow cloning" do @resource.depth 5 expected_cmd = "git clone --depth 5 \"git://github.com/opscode/chef.git\" \"/my/deploy/dir\"" @provider.should_receive(:shell_out!).with(expected_cmd, :log_tag => "git[web2.0 app]") @provider.clone end it "compiles a clone command with a remote other than ``origin''" do @resource.remote "opscode" expected_cmd = "git clone -o opscode \"git://github.com/opscode/chef.git\" \"/my/deploy/dir\"" @provider.should_receive(:shell_out!).with(expected_cmd, :log_tag => "git[web2.0 app]") @provider.clone end it "runs a checkout command with default options" do expected_cmd = 'git checkout -b deploy d35af14d41ae22b19da05d7d03a0bafc321b244c' @provider.should_receive(:shell_out!).with(expected_cmd, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]") @provider.checkout end it "runs an enable_submodule command" do @resource.enable_submodules true expected_cmd = "git submodule sync" @provider.should_receive(:shell_out!).with(expected_cmd, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]") expected_cmd = "git submodule update --init --recursive" @provider.should_receive(:shell_out!).with(expected_cmd, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]") @provider.enable_submodules end it "does nothing for enable_submodules if resource.enable_submodules #=> false" do @provider.should_not_receive(:shell_out!) @provider.enable_submodules end it "runs a sync command with default options" do @provider.should_receive(:setup_remote_tracking_branches).with(@resource.remote, @resource.repository) expected_cmd = "git fetch origin && git fetch origin --tags && git reset --hard d35af14d41ae22b19da05d7d03a0bafc321b244c" @provider.should_receive(:shell_out!).with(expected_cmd, :cwd=> "/my/deploy/dir", :log_tag => "git[web2.0 app]") @provider.fetch_updates end it "runs a sync command with the user and group specified in the resource" do @resource.user("whois") @resource.group("thisis") @provider.should_receive(:setup_remote_tracking_branches).with(@resource.remote, @resource.repository) expected_cmd = "git fetch origin && git fetch origin --tags && git reset --hard d35af14d41ae22b19da05d7d03a0bafc321b244c" @provider.should_receive(:shell_out!).with(expected_cmd, :cwd => "/my/deploy/dir", :user => "whois", :group => "thisis", :log_tag => "git[web2.0 app]") @provider.fetch_updates end it "configures remote tracking branches when remote is ``origin''" do @resource.remote "origin" @provider.should_receive(:setup_remote_tracking_branches).with(@resource.remote, @resource.repository) fetch_command = "git fetch origin && git fetch origin --tags && git reset --hard d35af14d41ae22b19da05d7d03a0bafc321b244c" @provider.should_receive(:shell_out!).with(fetch_command, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]") @provider.fetch_updates end it "configures remote tracking branches when remote is not ``origin''" do @resource.remote "opscode" @provider.should_receive(:setup_remote_tracking_branches).with(@resource.remote, @resource.repository) fetch_command = "git fetch opscode && git fetch opscode --tags && git reset --hard d35af14d41ae22b19da05d7d03a0bafc321b244c" @provider.should_receive(:shell_out!).with(fetch_command, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]") @provider.fetch_updates end context "configuring remote tracking branches" do it "checks if a remote with this name already exists" do command_response = double('shell_out') command_response.stub(:exitstatus) { 1 } expected_command = "git config --get remote.#{@resource.remote}.url" @provider.should_receive(:shell_out!).with(expected_command, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]", :returns => [0,1,2]).and_return(command_response) add_remote_command = "git remote add #{@resource.remote} #{@resource.repository}" @provider.should_receive(:shell_out!).with(add_remote_command, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]") @provider.setup_remote_tracking_branches(@resource.remote, @resource.repository) end it "runs the config with the user and group specified in the resource" do @resource.user("whois") @resource.group("thisis") command_response = double('shell_out') command_response.stub(:exitstatus) { 1 } expected_command = "git config --get remote.#{@resource.remote}.url" @provider.should_receive(:shell_out!).with(expected_command, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]", :user => "whois", :group => "thisis", :returns => [0,1,2]).and_return(command_response) add_remote_command = "git remote add #{@resource.remote} #{@resource.repository}" @provider.should_receive(:shell_out!).with(add_remote_command, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]", :user => "whois", :group => "thisis") @provider.setup_remote_tracking_branches(@resource.remote, @resource.repository) end describe "when a remote with a given name hasn't been configured yet" do it "adds a new remote " do command_response = double('shell_out') command_response.stub(:exitstatus) { 1 } check_remote_command = "git config --get remote.#{@resource.remote}.url" @provider.should_receive(:shell_out!).with(check_remote_command, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]", :returns => [0,1,2]).and_return(command_response) expected_command = "git remote add #{@resource.remote} #{@resource.repository}" @provider.should_receive(:shell_out!).with(expected_command, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]") @provider.setup_remote_tracking_branches(@resource.remote, @resource.repository) end end describe "when a remote with a given name has already been configured" do it "updates remote url when the url is different" do command_response = double('shell_out') command_response.stub(:exitstatus) { 0 } command_response.stub(:stdout) { "some_other_url" } check_remote_command = "git config --get remote.#{@resource.remote}.url" @provider.should_receive(:shell_out!).with(check_remote_command, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]", :returns => [0,1,2]).and_return(command_response) expected_command = "git config --replace-all remote.#{@resource.remote}.url #{@resource.repository}" @provider.should_receive(:shell_out!).with(expected_command, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]") @provider.setup_remote_tracking_branches(@resource.remote, @resource.repository) end it "doesn't update remote url when the url is the same" do command_response = double('shell_out') command_response.stub(:exitstatus) { 0 } command_response.stub(:stdout) { @resource.repository } check_remote_command = "git config --get remote.#{@resource.remote}.url" @provider.should_receive(:shell_out!).with(check_remote_command, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]", :returns => [0,1,2]).and_return(command_response) unexpected_command = "git config --replace-all remote.#{@resource.remote}.url #{@resource.repository}" @provider.should_not_receive(:shell_out!).with(unexpected_command, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]") @provider.setup_remote_tracking_branches(@resource.remote, @resource.repository) end it "resets remote url when it has multiple values" do command_response = double('shell_out') command_response.stub(:exitstatus) { 2 } check_remote_command = "git config --get remote.#{@resource.remote}.url" @provider.should_receive(:shell_out!).with(check_remote_command, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]", :returns => [0,1,2]).and_return(command_response) expected_command = "git config --replace-all remote.#{@resource.remote}.url #{@resource.repository}" @provider.should_receive(:shell_out!).with(expected_command, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]") @provider.setup_remote_tracking_branches(@resource.remote, @resource.repository) end end end it "raises an error if the git clone command would fail because the enclosing directory doesn't exist" do @provider.stub!(:shell_out!) lambda {@provider.run_action(:sync)}.should raise_error(Chef::Exceptions::MissingParentDirectory) end it "does a checkout by cloning the repo and then enabling submodules" do # will be invoked in load_current_resource ::File.stub!(:exist?).with("/my/deploy/dir/.git").and_return(false) ::File.stub!(:exist?).with("/my/deploy/dir").and_return(true) ::File.stub!(:directory?).with("/my/deploy").and_return(true) ::Dir.stub!(:entries).with("/my/deploy/dir").and_return(['.','..']) @provider.should_receive(:clone) @provider.should_receive(:checkout) @provider.should_receive(:enable_submodules) @provider.run_action(:checkout) # Even though an actual run will cause an update to occur, the fact that we've stubbed out # the actions above will prevent updates from registering # @resource.should be_updated end # REGRESSION TEST: on some OSes, the entries from an empty directory will be listed as # ['..', '.'] but this shouldn't change the behavior it "does a checkout by cloning the repo and then enabling submodules when the directory entries are listed as %w{.. .}" do ::File.stub!(:exist?).with("/my/deploy/dir/.git").and_return(false) ::File.stub!(:exist?).with("/my/deploy/dir").and_return(false) ::File.stub!(:directory?).with("/my/deploy").and_return(true) ::Dir.stub!(:entries).with("/my/deploy/dir").and_return(['..','.']) @provider.should_receive(:clone) @provider.should_receive(:checkout) @provider.should_receive(:enable_submodules) @provider.should_receive(:add_remotes) @provider.run_action(:checkout) # @resource.should be_updated end it "should not checkout if the destination exists or is a non empty directory" do # will be invoked in load_current_resource ::File.stub!(:exist?).with("/my/deploy/dir/.git").and_return(false) ::File.stub!(:exist?).with("/my/deploy/dir").and_return(true) ::File.stub!(:directory?).with("/my/deploy").and_return(true) ::Dir.stub!(:entries).with("/my/deploy/dir").and_return(['.','..','foo','bar']) @provider.should_not_receive(:clone) @provider.should_not_receive(:checkout) @provider.should_not_receive(:enable_submodules) @provider.should_not_receive(:add_remotes) @provider.run_action(:checkout) @resource.should_not be_updated end it "syncs the code by updating the source when the repo has already been checked out" do ::File.should_receive(:exist?).with("/my/deploy/dir/.git").and_return(true) ::File.stub!(:directory?).with("/my/deploy").and_return(true) @provider.should_receive(:find_current_revision).exactly(2).and_return('d35af14d41ae22b19da05d7d03a0bafc321b244c') @provider.should_not_receive(:fetch_updates) @provider.should_receive(:add_remotes) @provider.run_action(:sync) @resource.should_not be_updated end it "marks the resource as updated when the repo is updated and gets a new version" do ::File.should_receive(:exist?).with("/my/deploy/dir/.git").and_return(true) ::File.stub!(:directory?).with("/my/deploy").and_return(true) # invoked twice - first time from load_current_resource @provider.should_receive(:find_current_revision).exactly(2).and_return('d35af14d41ae22b19da05d7d03a0bafc321b244c') @provider.stub!(:target_revision).and_return('28af684d8460ba4793eda3e7ac238c864a5d029a') @provider.should_receive(:fetch_updates) @provider.should_receive(:enable_submodules) @provider.should_receive(:add_remotes) @provider.run_action(:sync) # @resource.should be_updated end it "does not fetch any updates if the remote revision matches the current revision" do ::File.should_receive(:exist?).with("/my/deploy/dir/.git").and_return(true) ::File.stub!(:directory?).with("/my/deploy").and_return(true) @provider.stub!(:find_current_revision).and_return('d35af14d41ae22b19da05d7d03a0bafc321b244c') @provider.stub!(:target_revision).and_return('d35af14d41ae22b19da05d7d03a0bafc321b244c') @provider.should_not_receive(:fetch_updates) @provider.should_receive(:add_remotes) @provider.run_action(:sync) @resource.should_not be_updated end it "clones the repo instead of fetching it if the deploy directory doesn't exist" do ::File.stub!(:directory?).with("/my/deploy").and_return(true) ::File.should_receive(:exist?).with("/my/deploy/dir/.git").exactly(2).and_return(false) @provider.should_receive(:action_checkout) @provider.should_not_receive(:shell_out!) @provider.run_action(:sync) # @resource.should be_updated end it "clones the repo instead of fetching updates if the deploy directory is empty" do ::File.should_receive(:exist?).with("/my/deploy/dir/.git").exactly(2).and_return(false) ::File.stub!(:directory?).with("/my/deploy").and_return(true) ::File.stub!(:directory?).with("/my/deploy/dir").and_return(true) @provider.stub!(:sync_command).and_return("huzzah!") @provider.should_receive(:action_checkout) @provider.should_not_receive(:shell_out!).with("huzzah!", :cwd => "/my/deploy/dir") @provider.run_action(:sync) #@resource.should be_updated end it "does an export by cloning the repo then removing the .git directory" do @provider.should_receive(:action_checkout) FileUtils.should_receive(:rm_rf).with(@resource.destination + "/.git") @provider.run_action(:export) @resource.should be_updated end describe "calling add_remotes" do it "adds a new remote for each entry in additional remotes hash" do @resource.additional_remotes({:opscode => "opscode_repo_url", :another_repo => "some_other_repo_url"}) STDOUT.stub(:tty?).and_return(false) command_response = double('shell_out') command_response.stub(:exitstatus) { 0 } @resource.additional_remotes.each_pair do |remote_name, remote_url| @provider.should_receive(:setup_remote_tracking_branches).with(remote_name, remote_url) end @provider.add_remotes end end describe "calling multiple_remotes?" do before(:each) do @command_response = double('shell_out') end describe "when check remote command returns with status 2" do it "returns true" do @command_response.stub(:exitstatus) { 2 } @provider.multiple_remotes?(@command_response).should be_true end end describe "when check remote command returns with status 0" do it "returns false" do @command_response.stub(:exitstatus) { 0 } @provider.multiple_remotes?(@command_response).should be_false end end describe "when check remote command returns with status 0" do it "returns false" do @command_response.stub(:exitstatus) { 1 } @provider.multiple_remotes?(@command_response).should be_false end end end describe "calling remote_matches?" do before(:each) do @command_response = double('shell_out') end describe "when output of the check remote command matches the repository url" do it "returns true" do @command_response.stub(:exitstatus) { 0 } @command_response.stub(:stdout) { @resource.repository } @provider.remote_matches?(@resource.repository, @command_response).should be_true end end describe "when output of the check remote command doesn't match the repository url" do it "returns false" do @command_response.stub(:exitstatus) { 0 } @command_response.stub(:stdout) { @resource.repository + "test" } @provider.remote_matches?(@resource.repository, @command_response).should be_false end end end end chef-11.8.2/spec/unit/provider/group_spec.rb0000644000004100000410000002203712254362222021002 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::User do before do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Group.new("wheel", @run_context) @new_resource.gid 500 @new_resource.members "aj" @provider = Chef::Provider::Group.new(@new_resource, @run_context) @current_resource = Chef::Resource::Group.new("aj", @run_context) @current_resource.gid 500 @current_resource.members "aj" @provider.current_resource = @current_resource @pw_group = mock("Struct::Group", :name => "wheel", :gid => 20, :mem => [ "root", "aj" ] ) Etc.stub!(:getgrnam).with('wheel').and_return(@pw_group) end it "assumes the group exists by default" do @provider.group_exists.should be_true end describe "when establishing the current state of the group" do it "sets the group name of the current resource to the group name of the new resource" do @provider.load_current_resource @provider.current_resource.group_name.should == 'wheel' end it "does not modify the desired gid if set" do @provider.load_current_resource @new_resource.gid.should == 500 end it "sets the desired gid to the current gid if none is set" do @new_resource.instance_variable_set(:@gid, nil) @provider.load_current_resource @new_resource.gid.should == 20 end it "looks up the group in /etc/group with getgrnam" do Etc.should_receive(:getgrnam).with(@new_resource.group_name).and_return(@pw_group) @provider.load_current_resource @provider.current_resource.gid.should == 20 @provider.current_resource.members.should == %w{root aj} end it "should flip the value of exists if it cannot be found in /etc/group" do Etc.stub!(:getgrnam).and_raise(ArgumentError) @provider.load_current_resource @provider.group_exists.should be_false end it "should return the current resource" do @provider.load_current_resource.should equal(@provider.current_resource) end end describe "when determining if the system is already in the target state" do [ :gid, :members ].each do |attribute| it "should return true if #{attribute} doesn't match" do @current_resource.stub!(attribute).and_return("looooooooooooooooooool") @provider.compare_group.should be_true end end it "should return false if gid and members are equal" do @provider.compare_group.should be_false end it "should return false if append is true and the group member(s) already exists" do @current_resource.members << "extra_user" @new_resource.stub!(:append).and_return(true) @provider.compare_group.should be_false end it "should return true if append is true and the group member(s) do not already exist" do @new_resource.members << "extra_user" @new_resource.stub!(:append).and_return(true) @provider.compare_group.should be_true end end describe "when creating a group" do it "should call create_group if the group does not exist" do @provider.group_exists = false @provider.should_receive(:create_group).and_return(true) @provider.run_action(:create) end it "should set the new_resources updated flag when it creates the group" do @provider.group_exists = false @provider.stub!(:create_group) @provider.run_action(:create) @provider.new_resource.should be_updated end it "should check to see if the group has mismatched attributes if the group exists" do @provider.group_exists = true @provider.stub!(:compare_group).and_return(false) @provider.run_action(:create) @provider.new_resource.should_not be_updated end it "should call manage_group if the group exists and has mismatched attributes" do @provider.group_exists = true @provider.stub!(:compare_group).and_return(true) @provider.should_receive(:manage_group).and_return(true) @provider.run_action(:create) end it "should set the new_resources updated flag when it creates the group if we call manage_group" do @provider.group_exists = true @provider.stub!(:compare_group).and_return(true) @provider.stub!(:manage_group).and_return(true) @provider.run_action(:create) @new_resource.should be_updated end end describe "when removing a group" do it "should not call remove_group if the group does not exist" do @provider.group_exists = false @provider.should_not_receive(:remove_group) @provider.run_action(:remove) @provider.new_resource.should_not be_updated end it "should call remove_group if the group exists" do @provider.group_exists = true @provider.should_receive(:remove_group) @provider.run_action(:remove) @provider.new_resource.should be_updated end end describe "when updating a group" do before(:each) do @provider.group_exists = true @provider.stub!(:manage_group).and_return(true) end it "should run manage_group if the group exists and has mismatched attributes" do @provider.should_receive(:compare_group).and_return(true) @provider.should_receive(:manage_group).and_return(true) @provider.run_action(:manage) end it "should set the new resources updated flag to true if manage_group is called" do @provider.stub!(:compare_group).and_return(true) @provider.stub!(:manage_group).and_return(true) @provider.run_action(:manage) @new_resource.should be_updated end it "should not run manage_group if the group does not exist" do @provider.group_exists = false @provider.should_not_receive(:manage_group) @provider.run_action(:manage) end it "should not run manage_group if the group exists but has no differing attributes" do @provider.should_receive(:compare_group).and_return(false) @provider.should_not_receive(:manage_group) @provider.run_action(:manage) end end describe "when modifying the group" do before(:each) do @provider.group_exists = true @provider.stub!(:manage_group).and_return(true) end it "should run manage_group if the group exists and has mismatched attributes" do @provider.should_receive(:compare_group).and_return(true) @provider.should_receive(:manage_group).and_return(true) @provider.run_action(:modify) end it "should set the new resources updated flag to true if manage_group is called" do @provider.stub!(:compare_group).and_return(true) @provider.stub!(:manage_group).and_return(true) @provider.run_action(:modify) @new_resource.should be_updated end it "should not run manage_group if the group exists but has no differing attributes" do @provider.should_receive(:compare_group).and_return(false) @provider.should_not_receive(:manage_group) @provider.run_action(:modify) end it "should raise a Chef::Exceptions::Group if the group doesn't exist" do @provider.group_exists = false lambda { @provider.run_action(:modify) }.should raise_error(Chef::Exceptions::Group) end end describe "when determining the reason for a change" do it "should report which group members are missing if members are missing and appending to the group" do @new_resource.members << "user1" @new_resource.members << "user2" @new_resource.stub!(:append).and_return true @provider.compare_group.should be_true @provider.change_desc.should == "add missing member(s): user1, user2" end it "should report that the group members will be overwritten if not appending" do @new_resource.members << "user1" @new_resource.stub!(:append).and_return false @provider.compare_group.should be_true @provider.change_desc.should == "replace group members with new list of members" end it "should report the gid will be changed when it does not match" do @current_resource.stub!(:gid).and_return("BADF00D") @provider.compare_group.should be_true @provider.change_desc.should == "change gid #{@current_resource.gid} to #{@new_resource.gid}" end it "should report no change reason when no change is required" do @provider.compare_group.should be_false @provider.change_desc.should == nil end end end chef-11.8.2/spec/unit/provider/file/0000755000004100000410000000000012254362222017222 5ustar www-datawww-datachef-11.8.2/spec/unit/provider/file/content_spec.rb0000644000004100000410000000526212254362222022240 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::File::Content do # # mock setup # let(:current_resource) do mock("Chef::Provider::File::Resource (current)") end let(:enclosing_directory) { canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates"))) } let(:resource_path) { canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt"))) } let(:new_resource) do mock("Chef::Provider::File::Resource (new)", :name => "seattle.txt", :path => resource_path) end let(:run_context) do mock("Chef::RunContext") end # # subject # let(:content) do Chef::Provider::File::Content.new(new_resource, current_resource, run_context) end describe "when the resource has a content attribute set" do before do new_resource.stub!(:content).and_return("Do do do do, do do do do, do do do do, do do do do") end it "returns a tempfile" do content.tempfile.should be_a_kind_of(Tempfile) end it "the tempfile contents should match the resource contents" do IO.read(content.tempfile.path).should == new_resource.content end it "returns a tempfile in the tempdir when :file_staging_uses_destdir is not set" do Chef::Config[:file_staging_uses_destdir] = false content.tempfile.path.start_with?(Dir::tmpdir).should be_true canonicalize_path(content.tempfile.path).start_with?(enclosing_directory).should be_false end it "returns a tempfile in the destdir when :file_desployment_uses_destdir is not set" do Chef::Config[:file_staging_uses_destdir] = true content.tempfile.path.start_with?(Dir::tmpdir).should be_false canonicalize_path(content.tempfile.path).start_with?(enclosing_directory).should be_true end end describe "when the resource does not have a content attribute set" do before do new_resource.stub!(:content).and_return(nil) end it "should return nil instead of a tempfile" do content.tempfile.should be_nil end end end chef-11.8.2/spec/unit/provider/cron_spec.rb0000644000004100000410000005643512254362222020620 0ustar www-datawww-data# # Author:: Bryan McLellan (btm@loftninjas.org) # Copyright:: Copyright (c) 2009 Bryan McLellan # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Cron do before do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Cron.new("cronhole some stuff", @run_context) @new_resource.user "root" @new_resource.minute "30" @new_resource.command "/bin/true" @provider = Chef::Provider::Cron.new(@new_resource, @run_context) end describe "when examining the current system state" do context "with no crontab for the user" do before :each do @provider.stub!(:read_crontab).and_return(nil) end it "should set cron_empty" do @provider.load_current_resource @provider.cron_empty.should == true @provider.cron_exists.should == false end it "should report an empty crontab" do Chef::Log.should_receive(:debug).with("Cron empty for '#{@new_resource.user}'") @provider.load_current_resource end end context "with no matching entry in the user's crontab" do before :each do @provider.stub!(:read_crontab).and_return(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: something else * 5 * * * /bin/true # Another comment CRONTAB end it "should not set cron_exists or cron_empty" do @provider.load_current_resource @provider.cron_exists.should == false @provider.cron_empty.should == false end it "should report no entry found" do Chef::Log.should_receive(:debug).with("Cron '#{@new_resource.name}' not found") @provider.load_current_resource end it "should not fail if there's an existing cron with a numerical argument" do @provider.stub!(:read_crontab).and_return(<<-CRONTAB) # Chef Name: foo[bar] (baz) 21 */4 * * * some_prog 1234567 CRONTAB lambda { @provider.load_current_resource }.should_not raise_error end end context "with a matching entry in the user's crontab" do before :each do @provider.stub!(:read_crontab).and_return(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff * 5 * 1 * /bin/true param1 param2 # Chef Name: something else 2 * 1 * * /bin/false # Another comment CRONTAB end it "should set cron_exists" do @provider.load_current_resource @provider.cron_exists.should == true @provider.cron_empty.should == false end it "should pull the details out of the cron line" do cron = @provider.load_current_resource cron.minute.should == '*' cron.hour.should == '5' cron.day.should == '*' cron.month.should == '1' cron.weekday.should == '*' cron.command.should == '/bin/true param1 param2' end it "should pull env vars out" do @provider.stub!(:read_crontab).and_return(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff MAILTO=foo@example.com SHELL=/bin/foosh PATH=/bin:/foo HOME=/home/foo * 5 * 1 * /bin/true param1 param2 # Chef Name: something else 2 * 1 * * /bin/false # Another comment CRONTAB cron = @provider.load_current_resource cron.mailto.should == 'foo@example.com' cron.shell.should == '/bin/foosh' cron.path.should == '/bin:/foo' cron.home.should == '/home/foo' cron.minute.should == '*' cron.hour.should == '5' cron.day.should == '*' cron.month.should == '1' cron.weekday.should == '*' cron.command.should == '/bin/true param1 param2' end it "should parse and load generic and standard environment variables from cron entry" do @provider.stub!(:read_crontab).and_return(<<-CRONTAB) # Chef Name: cronhole some stuff MAILTO=warn@example.com TEST=lol FLAG=1 * 5 * * * /bin/true CRONTAB cron = @provider.load_current_resource cron.mailto.should == "warn@example.com" cron.environment.should == {"TEST" => "lol", "FLAG" => "1"} end it "should not break with variabels that match the cron resource internals" do @provider.stub!(:read_crontab).and_return(<<-CRONTAB) # Chef Name: cronhole some stuff MINUTE=40 HOUR=midnight TEST=lol ENVIRONMENT=production * 5 * * * /bin/true CRONTAB cron = @provider.load_current_resource cron.minute.should == '*' cron.hour.should == '5' cron.environment.should == {"MINUTE" => "40", "HOUR" => "midnight", "TEST" => "lol", "ENVIRONMENT" => "production"} end it "should report the match" do Chef::Log.should_receive(:debug).with("Found cron '#{@new_resource.name}'") @provider.load_current_resource end end context "with a matching entry in the user's crontab using month names and weekday names (#CHEF-3178)" do before :each do @provider.stub!(:read_crontab).and_return(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff * 5 * Jan Mon /bin/true param1 param2 # Chef Name: something else 2 * 1 * * /bin/false # Another comment CRONTAB end it "should set cron_exists" do @provider.load_current_resource @provider.cron_exists.should == true @provider.cron_empty.should == false end it "should pull the details out of the cron line" do cron = @provider.load_current_resource cron.minute.should == '*' cron.hour.should == '5' cron.day.should == '*' cron.month.should == 'Jan' cron.weekday.should == 'Mon' cron.command.should == '/bin/true param1 param2' end it "should report the match" do Chef::Log.should_receive(:debug).with("Found cron '#{@new_resource.name}'") @provider.load_current_resource end end context "with a matching entry without a crontab line" do it "should set cron_exists and leave current_resource values at defaults" do @provider.stub!(:read_crontab).and_return(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff CRONTAB cron = @provider.load_current_resource @provider.cron_exists.should == true cron.minute.should == '*' cron.hour.should == '*' cron.day.should == '*' cron.month.should == '*' cron.weekday.should == '*' cron.command.should == nil end it "should not pick up a commented out crontab line" do @provider.stub!(:read_crontab).and_return(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff #* 5 * 1 * /bin/true param1 param2 CRONTAB cron = @provider.load_current_resource @provider.cron_exists.should == true cron.minute.should == '*' cron.hour.should == '*' cron.day.should == '*' cron.month.should == '*' cron.weekday.should == '*' cron.command.should == nil end it "should not pick up a later crontab entry" do @provider.stub!(:read_crontab).and_return(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff #* 5 * 1 * /bin/true param1 param2 # Chef Name: something else 2 * 1 * * /bin/false # Another comment CRONTAB cron = @provider.load_current_resource @provider.cron_exists.should == true cron.minute.should == '*' cron.hour.should == '*' cron.day.should == '*' cron.month.should == '*' cron.weekday.should == '*' cron.command.should == nil end end end describe "cron_different?" do before :each do @current_resource = Chef::Resource::Cron.new("cronhole some stuff") @current_resource.user "root" @current_resource.minute "30" @current_resource.command "/bin/true" @provider.current_resource = @current_resource end [:minute, :hour, :day, :month, :weekday, :command, :mailto, :path, :shell, :home].each do |attribute| it "should return true if #{attribute} doesn't match" do @new_resource.send(attribute, "something_else") @provider.cron_different?.should eql(true) end end it "should return true if environment doesn't match" do @new_resource.environment "FOO" => "something_else" @provider.cron_different?.should eql(true) end it "should return false if the objects are identical" do @provider.cron_different?.should == false end end describe "action_create" do before :each do @provider.stub!(:write_crontab) @provider.stub!(:read_crontab).and_return(nil) end context "when there is no existing crontab" do before :each do @provider.cron_exists = false @provider.cron_empty = true end it "should create a crontab with the entry" do @provider.should_receive(:write_crontab).with(<<-ENDCRON) # Chef Name: cronhole some stuff 30 * * * * /bin/true ENDCRON @provider.run_action(:create) end it "should include env variables that are set" do @new_resource.mailto 'foo@example.com' @new_resource.path '/usr/bin:/my/custom/path' @new_resource.shell '/bin/foosh' @new_resource.home '/home/foo' @new_resource.environment "TEST" => "LOL" @provider.should_receive(:write_crontab).with(<<-ENDCRON) # Chef Name: cronhole some stuff MAILTO=foo@example.com PATH=/usr/bin:/my/custom/path SHELL=/bin/foosh HOME=/home/foo TEST=LOL 30 * * * * /bin/true ENDCRON @provider.run_action(:create) end it "should mark the resource as updated" do @provider.run_action(:create) @new_resource.should be_updated_by_last_action end it "should log the action" do Chef::Log.should_receive(:info).with("cron[cronhole some stuff] added crontab entry") @provider.run_action(:create) end end context "when there is a crontab with no matching section" do before :each do @provider.cron_exists = false @provider.stub!(:read_crontab).and_return(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: something else 2 * 1 * * /bin/false # Another comment CRONTAB end it "should add the entry to the crontab" do @provider.should_receive(:write_crontab).with(<<-ENDCRON) 0 2 * * * /some/other/command # Chef Name: something else 2 * 1 * * /bin/false # Another comment # Chef Name: cronhole some stuff 30 * * * * /bin/true ENDCRON @provider.run_action(:create) end it "should include env variables that are set" do @new_resource.mailto 'foo@example.com' @new_resource.path '/usr/bin:/my/custom/path' @new_resource.shell '/bin/foosh' @new_resource.home '/home/foo' @new_resource.environment "TEST" => "LOL" @provider.should_receive(:write_crontab).with(<<-ENDCRON) 0 2 * * * /some/other/command # Chef Name: something else 2 * 1 * * /bin/false # Another comment # Chef Name: cronhole some stuff MAILTO=foo@example.com PATH=/usr/bin:/my/custom/path SHELL=/bin/foosh HOME=/home/foo TEST=LOL 30 * * * * /bin/true ENDCRON @provider.run_action(:create) end it "should mark the resource as updated" do @provider.run_action(:create) @new_resource.should be_updated_by_last_action end it "should log the action" do Chef::Log.should_receive(:info).with("cron[cronhole some stuff] added crontab entry") @provider.run_action(:create) end end context "when there is a crontab with a matching but different section" do before :each do @provider.cron_exists = true @provider.stub!(:cron_different?).and_return(true) @provider.stub!(:read_crontab).and_return(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff 30 * * 3 * /bin/true # Chef Name: something else 2 * 1 * * /bin/false # Another comment CRONTAB end it "should update the crontab entry" do @provider.should_receive(:write_crontab).with(<<-ENDCRON) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff 30 * * * * /bin/true # Chef Name: something else 2 * 1 * * /bin/false # Another comment ENDCRON @provider.run_action(:create) end it "should include env variables that are set" do @new_resource.mailto 'foo@example.com' @new_resource.path '/usr/bin:/my/custom/path' @new_resource.shell '/bin/foosh' @new_resource.home '/home/foo' @new_resource.environment "TEST" => "LOL" @provider.should_receive(:write_crontab).with(<<-ENDCRON) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff MAILTO=foo@example.com PATH=/usr/bin:/my/custom/path SHELL=/bin/foosh HOME=/home/foo TEST=LOL 30 * * * * /bin/true # Chef Name: something else 2 * 1 * * /bin/false # Another comment ENDCRON @provider.run_action(:create) end it "should mark the resource as updated" do @provider.run_action(:create) @new_resource.should be_updated_by_last_action end it "should log the action" do Chef::Log.should_receive(:info).with("cron[cronhole some stuff] updated crontab entry") @provider.run_action(:create) end end context "when there is a crontab with a matching section with no crontab line in it" do before :each do @provider.cron_exists = true @provider.stub!(:cron_different?).and_return(true) end it "should add the crontab to the entry" do @provider.stub!(:read_crontab).and_return(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff CRONTAB @provider.should_receive(:write_crontab).with(<<-ENDCRON) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff 30 * * * * /bin/true ENDCRON @provider.run_action(:create) end it "should not blat any following entries" do @provider.stub!(:read_crontab).and_return(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff #30 * * * * /bin/true # Chef Name: something else 2 * 1 * * /bin/false # Another comment CRONTAB @provider.should_receive(:write_crontab).with(<<-ENDCRON) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff 30 * * * * /bin/true #30 * * * * /bin/true # Chef Name: something else 2 * 1 * * /bin/false # Another comment ENDCRON @provider.run_action(:create) end it "should handle env vars with no crontab" do @provider.stub!(:read_crontab).and_return(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff MAILTO=bar@example.com PATH=/usr/bin:/my/custom/path SHELL=/bin/barsh HOME=/home/foo # Chef Name: something else 2 * 1 * * /bin/false # Another comment CRONTAB @new_resource.mailto 'foo@example.com' @new_resource.path '/usr/bin:/my/custom/path' @new_resource.shell '/bin/foosh' @new_resource.home '/home/foo' @provider.should_receive(:write_crontab).with(<<-ENDCRON) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff MAILTO=foo@example.com PATH=/usr/bin:/my/custom/path SHELL=/bin/foosh HOME=/home/foo 30 * * * * /bin/true # Chef Name: something else 2 * 1 * * /bin/false # Another comment ENDCRON @provider.run_action(:create) end end context "when there is a crontab with a matching and identical section" do before :each do @provider.cron_exists = true @provider.stub!(:cron_different?).and_return(false) @provider.stub!(:read_crontab).and_return(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff * 5 * * * /bin/true # Another comment CRONTAB end it "should not update the crontab" do @provider.should_not_receive(:write_crontab) @provider.run_action(:create) end it "should not mark the resource as updated" do @provider.run_action(:create) @new_resource.should_not be_updated_by_last_action end it "should log nothing changed" do Chef::Log.should_receive(:debug).with("Found cron '#{@new_resource.name}'") Chef::Log.should_receive(:debug).with("Skipping existing cron entry '#{@new_resource.name}'") @provider.run_action(:create) end end end describe "action_delete" do before :each do @provider.stub!(:write_crontab) @provider.stub!(:read_crontab).and_return(nil) end context "when the user's crontab has no matching section" do before :each do @provider.cron_exists = false end it "should do nothing" do @provider.should_not_receive(:write_crontab) Chef::Log.should_not_receive(:info) @provider.run_action(:delete) end it "should not mark the resource as updated" do @provider.run_action(:delete) @new_resource.should_not be_updated_by_last_action end end context "when the user has a crontab with a matching section" do before :each do @provider.cron_exists = true @provider.stub!(:read_crontab).and_return(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff 30 * * 3 * /bin/true # Chef Name: something else 2 * 1 * * /bin/false # Another comment CRONTAB end it "should remove the entry" do @provider.should_receive(:write_crontab).with(<<-ENDCRON) 0 2 * * * /some/other/command # Chef Name: something else 2 * 1 * * /bin/false # Another comment ENDCRON @provider.run_action(:delete) end it "should remove any env vars with the entry" do @provider.stub!(:read_crontab).and_return(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff MAILTO=foo@example.com FOO=test 30 * * 3 * /bin/true # Chef Name: something else 2 * 1 * * /bin/false # Another comment CRONTAB @provider.should_receive(:write_crontab).with(<<-ENDCRON) 0 2 * * * /some/other/command # Chef Name: something else 2 * 1 * * /bin/false # Another comment ENDCRON @provider.run_action(:delete) end it "should mark the resource as updated" do @provider.run_action(:delete) @new_resource.should be_updated_by_last_action end it "should log the action" do Chef::Log.should_receive(:info).with("#{@new_resource} deleted crontab entry") @provider.run_action(:delete) end end context "when the crontab has a matching section with no crontab line" do before :each do @provider.cron_exists = true end it "should remove the section" do @provider.stub!(:read_crontab).and_return(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff CRONTAB @provider.should_receive(:write_crontab).with(<<-ENDCRON) 0 2 * * * /some/other/command ENDCRON @provider.run_action(:delete) end it "should not blat following sections" do @provider.stub!(:read_crontab).and_return(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff #30 * * 3 * /bin/true # Chef Name: something else 2 * 1 * * /bin/false # Another comment CRONTAB @provider.should_receive(:write_crontab).with(<<-ENDCRON) 0 2 * * * /some/other/command #30 * * 3 * /bin/true # Chef Name: something else 2 * 1 * * /bin/false # Another comment ENDCRON @provider.run_action(:delete) end it "should remove any envvars with the section" do @provider.stub!(:read_crontab).and_return(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: cronhole some stuff MAILTO=foo@example.com #30 * * 3 * /bin/true # Chef Name: something else 2 * 1 * * /bin/false # Another comment CRONTAB @provider.should_receive(:write_crontab).with(<<-ENDCRON) 0 2 * * * /some/other/command #30 * * 3 * /bin/true # Chef Name: something else 2 * 1 * * /bin/false # Another comment ENDCRON @provider.run_action(:delete) end end end describe "read_crontab" do before :each do @status = mock("Status", :exitstatus => 0) @stdout = StringIO.new(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: something else * 5 * * * /bin/true # Another comment CRONTAB @provider.stub!(:popen4).and_yield(1234, StringIO.new, @stdout, StringIO.new).and_return(@status) end it "should call crontab -l with the user" do @provider.should_receive(:popen4).with("crontab -l -u #{@new_resource.user}").and_return(@status) @provider.send(:read_crontab) end it "should return the contents of the crontab" do crontab = @provider.send(:read_crontab) crontab.should == <<-CRONTAB 0 2 * * * /some/other/command # Chef Name: something else * 5 * * * /bin/true # Another comment CRONTAB end it "should return nil if the user has no crontab" do status = mock("Status", :exitstatus => 1) @provider.stub!(:popen4).and_return(status) @provider.send(:read_crontab).should == nil end it "should raise an exception if another error occurs" do status = mock("Status", :exitstatus => 2) @provider.stub!(:popen4).and_return(status) lambda do @provider.send(:read_crontab) end.should raise_error(Chef::Exceptions::Cron, "Error determining state of #{@new_resource.name}, exit: 2") end end describe "write_crontab" do before :each do @status = mock("Status", :exitstatus => 0) @stdin = StringIO.new @provider.stub!(:popen4).and_yield(1234, @stdin, StringIO.new, StringIO.new).and_return(@status) end it "should call crontab for the user" do @provider.should_receive(:popen4).with("crontab -u #{@new_resource.user} -", :waitlast => true).and_return(@status) @provider.send(:write_crontab, "Foo") end it "should write the given string to the crontab command" do @provider.send(:write_crontab, "Foo\n# wibble\n wah!!") @stdin.string.should == "Foo\n# wibble\n wah!!" end it "should raise an exception if the command returns non-zero" do @status.stub!(:exitstatus).and_return(1) lambda do @provider.send(:write_crontab, "Foo") end.should raise_error(Chef::Exceptions::Cron, "Error updating state of #{@new_resource.name}, exit: 1") end it "should raise an exception if the command die's and parent tries to write" do class WriteErrPipe def write(str) raise Errno::EPIPE, "Test" end end @status.stub!(:exitstatus).and_return(1) @provider.stub!(:popen4).and_yield(1234, WriteErrPipe.new, StringIO.new, StringIO.new).and_return(@status) Chef::Log.should_receive(:debug).with("Broken pipe - Test") lambda do @provider.send(:write_crontab, "Foo") end.should raise_error(Chef::Exceptions::Cron, "Error updating state of #{@new_resource.name}, exit: 1") end end end chef-11.8.2/spec/unit/provider/service_spec.rb0000644000004100000410000001377112254362222021313 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Service do before do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Service.new("chef") @current_resource = Chef::Resource::Service.new("chef") @provider = Chef::Provider::Service.new(@new_resource, @run_context) @provider.current_resource = @current_resource @provider.stub!(:load_current_resource) end describe "when enabling the service" do it "should enable the service if disabled and set the resource as updated" do @current_resource.enabled(false) @provider.should_receive(:enable_service).and_return(true) @provider.action_enable @provider.set_updated_status @provider.new_resource.should be_updated end it "should not enable the service if already enabled" do @current_resource.enabled(true) @provider.should_not_receive(:enable_service) @provider.action_enable @provider.set_updated_status @provider.new_resource.should_not be_updated end end describe "when disabling the service" do it "should disable the service if enabled and set the resource as updated" do @current_resource.stub!(:enabled).and_return(true) @provider.should_receive(:disable_service).and_return(true) @provider.run_action(:disable) @provider.new_resource.should be_updated end it "should not disable the service if already disabled" do @current_resource.stub!(:enabled).and_return(false) @provider.should_not_receive(:disable_service) @provider.run_action(:disable) @provider.new_resource.should_not be_updated end end describe "action_start" do it "should start the service if it isn't running and set the resource as updated" do @current_resource.running(false) @provider.should_receive(:start_service).with.and_return(true) @provider.run_action(:start) @provider.new_resource.should be_updated end it "should not start the service if already running" do @current_resource.running(true) @provider.should_not_receive(:start_service) @provider.run_action(:start) @provider.new_resource.should_not be_updated end end describe "action_stop" do it "should stop the service if it is running and set the resource as updated" do @current_resource.stub!(:running).and_return(true) @provider.should_receive(:stop_service).and_return(true) @provider.run_action(:stop) @provider.new_resource.should be_updated end it "should not stop the service if it's already stopped" do @current_resource.stub!(:running).and_return(false) @provider.should_not_receive(:stop_service) @provider.run_action(:stop) @provider.new_resource.should_not be_updated end end describe "action_restart" do before do @current_resource.supports(:restart => true) end it "should restart the service if it's supported and set the resource as updated" do @provider.should_receive(:restart_service).and_return(true) @provider.run_action(:restart) @provider.new_resource.should be_updated end it "should restart the service even if it isn't running and set the resource as updated" do @current_resource.stub!(:running).and_return(false) @provider.should_receive(:restart_service).and_return(true) @provider.run_action(:restart) @provider.new_resource.should be_updated end end describe "action_reload" do before do @new_resource.supports(:reload => true) end it "should raise an exception if reload isn't supported" do @new_resource.supports(:reload => false) @new_resource.stub!(:reload_command).and_return(false) lambda { @provider.run_action(:reload) }.should raise_error(Chef::Exceptions::UnsupportedAction) end it "should reload the service if it is running and set the resource as updated" do @current_resource.stub!(:running).and_return(true) @provider.should_receive(:reload_service).and_return(true) @provider.run_action(:reload) @provider.new_resource.should be_updated end it "should not reload the service if it's stopped" do @current_resource.stub!(:running).and_return(false) @provider.should_not_receive(:reload_service) @provider.run_action(:stop) @provider.new_resource.should_not be_updated end end it "delegates enable_service to subclasses" do lambda { @provider.enable_service }.should raise_error(Chef::Exceptions::UnsupportedAction) end it "delegates disable_service to subclasses" do lambda { @provider.disable_service }.should raise_error(Chef::Exceptions::UnsupportedAction) end it "delegates start_service to subclasses" do lambda { @provider.start_service }.should raise_error(Chef::Exceptions::UnsupportedAction) end it "delegates stop_service to subclasses" do lambda { @provider.stop_service }.should raise_error(Chef::Exceptions::UnsupportedAction) end it "delegates restart_service to subclasses" do lambda { @provider.restart_service }.should raise_error(Chef::Exceptions::UnsupportedAction) end it "delegates reload_service to subclasses" do lambda { @provider.reload_service }.should raise_error(Chef::Exceptions::UnsupportedAction) end end chef-11.8.2/spec/unit/provider/subversion_spec.rb0000644000004100000410000003143512254362222022047 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Subversion do before do @resource = Chef::Resource::Subversion.new("my app") @resource.repository "http://svn.example.org/trunk/" @resource.destination "/my/deploy/dir" @resource.revision "12345" @resource.svn_arguments(false) @resource.svn_info_args(false) @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @provider = Chef::Provider::Subversion.new(@resource, @run_context) end it "converts resource attributes to options for run_command and popen4" do @provider.run_options.should == {} @resource.user 'deployninja' @provider.run_options.should == {:user => "deployninja"} end context "determining the revision of the currently deployed code" do before do @stdout = mock("stdout") @stderr = mock("stderr") @exitstatus = mock("exitstatus") end it "sets the revision to nil if there isn't any deployed code yet" do ::File.should_receive(:exist?).with("/my/deploy/dir/.svn").and_return(false) @provider.find_current_revision.should be_nil end it "determines the current revision if there's a checkout with svn data available" do example_svn_info = "Path: .\n" + "URL: http://svn.example.org/trunk/myapp\n" + "Repository Root: http://svn.example.org\n" + "Repository UUID: d62ff500-7bbc-012c-85f1-0026b0e37c24\n" + "Revision: 11739\nNode Kind: directory\n" + "Schedule: normal\n" + "Last Changed Author: codeninja\n" + "Last Changed Rev: 11410\n" + # Last Changed Rev is preferred to Revision "Last Changed Date: 2009-03-25 06:09:56 -0600 (Wed, 25 Mar 2009)\n\n" ::File.should_receive(:exist?).at_least(1).times.with("/my/deploy/dir/.svn").and_return(true) ::File.should_receive(:directory?).with("/my/deploy/dir").and_return(true) ::Dir.should_receive(:chdir).with("/my/deploy/dir").and_yield @stdout.stub!(:string).and_return(example_svn_info) @stderr.stub!(:string).and_return("") @exitstatus.stub!(:exitstatus).and_return(0) expected_command = ["svn info", {:cwd=>"/my/deploy/dir"}] @provider.should_receive(:popen4).with(*expected_command). and_yield("no-pid", "no-stdin", @stdout,@stderr). and_return(@exitstatus) @provider.find_current_revision.should eql("11410") end it "gives nil as the current revision if the deploy dir isn't a SVN working copy" do example_svn_info = "svn: '/tmp/deploydir' is not a working copy\n" ::File.should_receive(:exist?).with("/my/deploy/dir/.svn").and_return(true) ::File.should_receive(:directory?).with("/my/deploy/dir").and_return(true) ::Dir.should_receive(:chdir).with("/my/deploy/dir").and_yield @stdout.stub!(:string).and_return(example_svn_info) @stderr.stub!(:string).and_return("") @exitstatus.stub!(:exitstatus).and_return(1) @provider.should_receive(:popen4).and_yield("no-pid", "no-stdin", @stdout,@stderr). and_return(@exitstatus) @provider.find_current_revision.should be_nil end it "finds the current revision when loading the current resource state" do # note: the test is kinda janky, but it provides regression coverage for CHEF-2092 @resource.instance_variable_set(:@action, :sync) @provider.should_receive(:find_current_revision).and_return("12345") @provider.load_current_resource @provider.current_resource.revision.should == "12345" end end it "creates the current_resource object and sets its revision to the current deployment's revision as long as we're not exporting" do @provider.stub!(:find_current_revision).and_return("11410") @provider.new_resource.instance_variable_set :@action, [:checkout] @provider.load_current_resource @provider.current_resource.name.should eql(@resource.name) @provider.current_resource.revision.should eql("11410") end context "resolving revisions to an integer" do before do @stdout = mock("stdout") @stderr = mock("stderr") @resource.svn_info_args "--no-auth-cache" end it "returns the revision number as is if it's already an integer" do @provider.revision_int.should eql("12345") end it "queries the server and resolves the revision if it's not an integer (i.e. 'HEAD')" do example_svn_info = "Path: .\n" + "URL: http://svn.example.org/trunk/myapp\n" + "Repository Root: http://svn.example.org\n" + "Repository UUID: d62ff500-7bbc-012c-85f1-0026b0e37c24\n" + "Revision: 11739\nNode Kind: directory\n" + "Schedule: normal\n" + "Last Changed Author: codeninja\n" + "Last Changed Rev: 11410\n" + # Last Changed Rev is preferred to Revision "Last Changed Date: 2009-03-25 06:09:56 -0600 (Wed, 25 Mar 2009)\n\n" exitstatus = mock("exitstatus") exitstatus.stub!(:exitstatus).and_return(0) @resource.revision "HEAD" @stdout.stub!(:string).and_return(example_svn_info) @stderr.stub!(:string).and_return("") expected_command = ["svn info http://svn.example.org/trunk/ --no-auth-cache -rHEAD", {:cwd=>Dir.tmpdir}] @provider.should_receive(:popen4).with(*expected_command). and_yield("no-pid","no-stdin",@stdout,@stderr). and_return(exitstatus) @provider.revision_int.should eql("11410") end it "returns a helpful message if data from `svn info` can't be parsed" do example_svn_info = "some random text from an error message\n" exitstatus = mock("exitstatus") exitstatus.stub!(:exitstatus).and_return(0) @resource.revision "HEAD" @stdout.stub!(:string).and_return(example_svn_info) @stderr.stub!(:string).and_return("") @provider.should_receive(:popen4).and_yield("no-pid","no-stdin",@stdout,@stderr). and_return(exitstatus) lambda {@provider.revision_int}.should raise_error(RuntimeError, "Could not parse `svn info` data: some random text from an error message") end it "responds to :revision_slug as an alias for revision_sha" do @provider.should respond_to(:revision_slug) end end it "generates a checkout command with default options" do @provider.checkout_command.should eql("svn checkout -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir") end it "generates a checkout command with authentication" do @resource.svn_username "deployNinja" @resource.svn_password "vanish!" @provider.checkout_command.should eql("svn checkout -q --username deployNinja --password vanish! " + "-r12345 http://svn.example.org/trunk/ /my/deploy/dir") end it "generates a checkout command with arbitrary options" do @resource.svn_arguments "--no-auth-cache" @provider.checkout_command.should eql("svn checkout --no-auth-cache -q -r12345 "+ "http://svn.example.org/trunk/ /my/deploy/dir") end it "generates a sync command with default options" do @provider.sync_command.should eql("svn update -q -r12345 /my/deploy/dir") end it "generates an export command with default options" do @provider.export_command.should eql("svn export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir") end it "doesn't try to find the current revision when loading the resource if running an export" do @provider.new_resource.instance_variable_set :@action, [:export] @provider.should_not_receive(:find_current_revision) @provider.load_current_resource end it "doesn't try to find the current revision when loading the resource if running a force export" do @provider.new_resource.instance_variable_set :@action, [:force_export] @provider.should_not_receive(:find_current_revision) @provider.load_current_resource end it "runs an export with the --force option" do ::File.stub!(:directory?).with("/my/deploy").and_return(true) expected_cmd = "svn export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir" @provider.should_receive(:run_command).with(:command => expected_cmd) @provider.run_action(:force_export) @resource.should be_updated end it "runs the checkout command for action_checkout" do ::File.stub!(:directory?).with("/my/deploy").and_return(true) expected_cmd = "svn checkout -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir" @provider.should_receive(:run_command).with(:command => expected_cmd) @provider.run_action(:checkout) @resource.should be_updated end it "raises an error if the svn checkout command would fail because the enclosing directory doesn't exist" do lambda {@provider.run_action(:sync)}.should raise_error(Chef::Exceptions::MissingParentDirectory) end it "should not checkout if the destination exists or is a non empty directory" do ::File.stub!(:exist?).with("/my/deploy/dir/.svn").and_return(false) ::File.stub!(:exist?).with("/my/deploy/dir").and_return(true) ::File.stub!(:directory?).with("/my/deploy").and_return(true) ::Dir.stub!(:entries).with("/my/deploy/dir").and_return(['.','..','foo','bar']) @provider.should_not_receive(:checkout_command) @provider.run_action(:checkout) @resource.should_not be_updated end it "runs commands with the user and group specified in the resource" do ::File.stub!(:directory?).with("/my/deploy").and_return(true) @resource.user "whois" @resource.group "thisis" expected_cmd = "svn checkout -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir" @provider.should_receive(:run_command).with(:command => expected_cmd, :user => "whois", :group => "thisis") @provider.run_action(:checkout) @resource.should be_updated end it "does a checkout for action_sync if there's no deploy dir" do ::File.stub!(:directory?).with("/my/deploy").and_return(true) ::File.should_receive(:exist?).with("/my/deploy/dir/.svn").twice.and_return(false) @provider.should_receive(:action_checkout) @provider.run_action(:sync) end it "does a checkout for action_sync if the deploy dir exists but is empty" do ::File.stub!(:directory?).with("/my/deploy").and_return(true) ::File.should_receive(:exist?).with("/my/deploy/dir/.svn").twice.and_return(false) @provider.should_receive(:action_checkout) @provider.run_action(:sync) end it "runs the sync_command on action_sync if the deploy dir exists and isn't empty" do ::File.stub!(:directory?).with("/my/deploy").and_return(true) ::File.should_receive(:exist?).with("/my/deploy/dir/.svn").and_return(true) @provider.stub!(:find_current_revision).and_return("11410") @provider.stub!(:current_revision_matches_target_revision?).and_return(false) expected_cmd = "svn update -q -r12345 /my/deploy/dir" @provider.should_receive(:run_command).with(:command => expected_cmd) @provider.run_action(:sync) @resource.should be_updated end it "does not fetch any updates if the remote revision matches the current revision" do ::File.stub!(:directory?).with("/my/deploy").and_return(true) ::File.should_receive(:exist?).with("/my/deploy/dir/.svn").and_return(true) @provider.stub!(:find_current_revision).and_return('12345') @provider.stub!(:current_revision_matches_target_revision?).and_return(true) @provider.run_action(:sync) @resource.should_not be_updated end it "runs the export_command on action_export" do ::File.stub!(:directory?).with("/my/deploy").and_return(true) expected_cmd = "svn export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir" @provider.should_receive(:run_command).with(:command => expected_cmd) @provider.run_action(:export) @resource.should be_updated end end chef-11.8.2/spec/unit/provider/link_spec.rb0000644000004100000410000002227612254362222020610 0ustar www-datawww-data# # Author:: AJ Christensen () # Author:: John Keiser () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'ostruct' require 'spec_helper' if Chef::Platform.windows? require 'chef/win32/file' #probably need this in spec_helper end describe Chef::Resource::Link, :not_supported_on_win2k3 do let(:provider) do node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new run_context = Chef::RunContext.new(node, {}, @events) Chef::Provider::Link.new(new_resource, run_context) end let(:new_resource) do result = Chef::Resource::Link.new("#{CHEF_SPEC_DATA}/fofile-link") result.to "#{CHEF_SPEC_DATA}/fofile" result end def canonicalize(path) Chef::Platform.windows? ? path.gsub('/', '\\') : path end describe "when the target is a symlink" do before(:each) do lstat = mock("stats", :ino => 5) lstat.stub!(:uid).and_return(501) lstat.stub!(:gid).and_return(501) lstat.stub!(:mode).and_return(0777) File.stub!(:lstat).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(lstat) provider.file_class.stub!(:symlink?).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(true) provider.file_class.stub!(:readlink).with("#{CHEF_SPEC_DATA}/fofile-link").and_return("#{CHEF_SPEC_DATA}/fofile") end describe "to a file that exists" do before do File.stub(:exist?).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(true) new_resource.owner 501 # only loaded in current_resource if present in new new_resource.group 501 provider.load_current_resource end it "should set the symlink target" do provider.current_resource.target_file.should == "#{CHEF_SPEC_DATA}/fofile-link" end it "should set the link type" do provider.current_resource.link_type.should == :symbolic end it "should update the source of the existing link with the links target" do provider.current_resource.to.should == canonicalize("#{CHEF_SPEC_DATA}/fofile") end it "should set the owner" do provider.current_resource.owner.should == 501 end it "should set the group" do provider.current_resource.group.should == 501 end # We test create in unit tests because there is no other way to ensure # it does no work. Other create and delete scenarios are covered in # the functional tests for links. context 'when the desired state is identical' do let(:new_resource) do result = Chef::Resource::Link.new("#{CHEF_SPEC_DATA}/fofile-link") result.to "#{CHEF_SPEC_DATA}/fofile" result end it 'create does no work' do provider.access_controls.should_not_receive(:set_all) provider.run_action(:create) end end end describe "to a file that doesn't exist" do before do File.stub!(:exist?).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(false) provider.file_class.stub!(:symlink?).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(true) provider.file_class.stub!(:readlink).with("#{CHEF_SPEC_DATA}/fofile-link").and_return("#{CHEF_SPEC_DATA}/fofile") new_resource.owner "501" # only loaded in current_resource if present in new new_resource.group "501" provider.load_current_resource end it "should set the symlink target" do provider.current_resource.target_file.should == "#{CHEF_SPEC_DATA}/fofile-link" end it "should set the link type" do provider.current_resource.link_type.should == :symbolic end it "should update the source of the existing link to the link's target" do provider.current_resource.to.should == canonicalize("#{CHEF_SPEC_DATA}/fofile") end it "should not set the owner" do provider.current_resource.owner.should be_nil end it "should not set the group" do provider.current_resource.group.should be_nil end end end describe "when the target doesn't exist" do before do File.stub!(:exists?).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(false) provider.file_class.stub!(:symlink?).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(false) provider.load_current_resource end it "should set the symlink target" do provider.current_resource.target_file.should == "#{CHEF_SPEC_DATA}/fofile-link" end it "should update the source of the existing link to nil" do provider.current_resource.to.should be_nil end it "should not set the owner" do provider.current_resource.owner.should == nil end it "should not set the group" do provider.current_resource.group.should == nil end end describe "when the target is a regular old file" do before do stat = mock("stats", :ino => 5) stat.stub!(:uid).and_return(501) stat.stub!(:gid).and_return(501) stat.stub!(:mode).and_return(0755) provider.file_class.stub!(:stat).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(stat) File.stub!(:exists?).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(true) provider.file_class.stub!(:symlink?).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(false) end describe "and the source does not exist" do before do File.stub!(:exists?).with("#{CHEF_SPEC_DATA}/fofile").and_return(false) provider.load_current_resource end it "should set the symlink target" do provider.current_resource.target_file.should == "#{CHEF_SPEC_DATA}/fofile-link" end it "should update the current source of the existing link with an empty string" do provider.current_resource.to.should == '' end it "should not set the owner" do provider.current_resource.owner.should == nil end it "should not set the group" do provider.current_resource.group.should == nil end end describe "and the source exists" do before do stat = mock("stats", :ino => 6) stat.stub!(:uid).and_return(502) stat.stub!(:gid).and_return(502) stat.stub!(:mode).and_return(0644) provider.file_class.stub!(:stat).with("#{CHEF_SPEC_DATA}/fofile").and_return(stat) File.stub!(:exists?).with("#{CHEF_SPEC_DATA}/fofile").and_return(true) provider.load_current_resource end it "should set the symlink target" do provider.current_resource.target_file.should == "#{CHEF_SPEC_DATA}/fofile-link" end it "should update the current source of the existing link with an empty string" do provider.current_resource.to.should == '' end it "should not set the owner" do provider.current_resource.owner.should == nil end it "should not set the group" do provider.current_resource.group.should == nil end end describe "and is hardlinked to the source" do before do stat = mock("stats", :ino => 5) stat.stub!(:uid).and_return(502) stat.stub!(:gid).and_return(502) stat.stub!(:mode).and_return(0644) provider.file_class.stub!(:stat).with("#{CHEF_SPEC_DATA}/fofile").and_return(stat) File.stub!(:exists?).with("#{CHEF_SPEC_DATA}/fofile").and_return(true) provider.load_current_resource end it "should set the symlink target" do provider.current_resource.target_file.should == "#{CHEF_SPEC_DATA}/fofile-link" end it "should set the link type" do provider.current_resource.link_type.should == :hard end it "should update the source of the existing link to the link's target" do provider.current_resource.to.should == canonicalize("#{CHEF_SPEC_DATA}/fofile") end it "should not set the owner" do provider.current_resource.owner.should == nil end it "should not set the group" do provider.current_resource.group.should == nil end # We test create in unit tests because there is no other way to ensure # it does no work. Other create and delete scenarios are covered in # the functional tests for links. context 'when the desired state is identical' do let(:new_resource) do result = Chef::Resource::Link.new("#{CHEF_SPEC_DATA}/fofile-link") result.to "#{CHEF_SPEC_DATA}/fofile" result.link_type :hard result end it 'create does no work' do provider.file_class.should_not_receive(:symlink) provider.file_class.should_not_receive(:link) provider.access_controls.should_not_receive(:set_all) provider.run_action(:create) end end end end end chef-11.8.2/spec/unit/provider/group/0000755000004100000410000000000012254362222017437 5ustar www-datawww-datachef-11.8.2/spec/unit/provider/group/windows_spec.rb0000644000004100000410000000705612254362222022500 0ustar www-datawww-data# # Author:: Doug MacEachern () # Copyright:: Copyright (c) 2010 VMware, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' class Chef class Util class Windows class NetGroup end end end end describe Chef::Provider::Group::Windows do before do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Group.new("staff") @net_group = mock("Chef::Util::Windows::NetGroup") Chef::Util::Windows::NetGroup.stub!(:new).and_return(@net_group) @provider = Chef::Provider::Group::Windows.new(@new_resource, @run_context) end describe "when creating the group" do it "should call @net_group.local_add" do @net_group.should_receive(:local_set_members).with([]) @net_group.should_receive(:local_add) @provider.create_group end end describe "manage_group" do before do @new_resource.members([ "us" ]) @current_resource = Chef::Resource::Group.new("staff") @current_resource.members [ "all", "your", "base" ] Chef::Util::Windows::NetGroup.stub!(:new).and_return(@net_group) @net_group.stub!(:local_add_members) @net_group.stub!(:local_set_members) @provider.current_resource = @current_resource end it "should call @net_group.local_set_members" do @new_resource.stub!(:append).and_return(false) @net_group.should_receive(:local_set_members).with(@new_resource.members) @provider.manage_group end it "should call @net_group.local_add_members" do @new_resource.stub!(:append).and_return(true) @net_group.should_receive(:local_add_members).with(@new_resource.members) @provider.manage_group end it "should call @net_group.local_set_members if append fails" do @new_resource.stub!(:append).and_return(true) @net_group.stub!(:local_add_members).and_raise(ArgumentError) @net_group.should_receive(:local_add_members).with(@new_resource.members) @net_group.should_receive(:local_set_members).with(@new_resource.members + @current_resource.members) @provider.manage_group end end describe "remove_group" do before do Chef::Util::Windows::NetGroup.stub!(:new).and_return(@net_group) @provider.stub!(:run_command).and_return(true) end it "should call @net_group.local_delete" do @net_group.should_receive(:local_delete) @provider.remove_group end end end describe Chef::Provider::Group::Windows, "NetGroup" do before do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Group.new("Creating a new group") @new_resource.group_name "Remote Desktop Users" end it 'sets group_name correctly' do Chef::Util::Windows::NetGroup.should_receive(:new).with("Remote Desktop Users") Chef::Provider::Group::Windows.new(@new_resource, @run_context) end end chef-11.8.2/spec/unit/provider/group/usermod_spec.rb0000644000004100000410000000722512254362222022462 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Group::Usermod do before do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Group.new("wheel") @new_resource.members [ "all", "your", "base" ] @provider = Chef::Provider::Group::Usermod.new(@new_resource, @run_context) @provider.stub!(:run_command) end describe "modify_group_members" do describe "with an empty members array" do before do @new_resource.stub!(:members).and_return([]) end it "should log an appropriate message" do Chef::Log.should_receive(:debug).with("group[wheel] not changing group members, the group has no members") @provider.modify_group_members end end describe "with supplied members" do platforms = { "openbsd" => "-G", "netbsd" => "-G", "solaris" => "-a -G", "suse" => "-a -G", "opensuse" => "-a -G", "smartos" => "-G" } before do @new_resource.stub!(:members).and_return(["all", "your", "base"]) File.stub!(:exists?).and_return(true) end it "should raise an error when setting the entire group directly" do @provider.define_resource_requirements @provider.load_current_resource @provider.instance_variable_set("@group_exists", true) @provider.action = :modify lambda { @provider.run_action(@provider.process_resource_requirements) }.should raise_error(Chef::Exceptions::Group, "setting group members directly is not supported by #{@provider.to_s}, must set append true in group") end platforms.each do |platform, flags| it "should usermod each user when the append option is set on #{platform}" do @node.automatic_attrs[:platform] = platform @new_resource.stub!(:append).and_return(true) @provider.should_receive(:run_command).with({:command => "usermod #{flags} wheel all"}) @provider.should_receive(:run_command).with({:command => "usermod #{flags} wheel your"}) @provider.should_receive(:run_command).with({:command => "usermod #{flags} wheel base"}) @provider.modify_group_members end end end end describe "when loading the current resource" do before(:each) do File.stub!(:exists?).and_return(false) @provider.define_resource_requirements end it "should raise an error if the required binary /usr/sbin/usermod doesn't exist" do File.stub!(:exists?).and_return(true) File.should_receive(:exists?).with("/usr/sbin/usermod").and_return(false) lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Group) end it "shouldn't raise an error if the required binaries exist" do File.stub!(:exists?).and_return(true) lambda { @provider.process_resource_requirements }.should_not raise_error(Chef::Exceptions::Group) end end end chef-11.8.2/spec/unit/provider/group/gpasswd_spec.rb0000644000004100000410000001011212254362222022441 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Group::Gpasswd, "modify_group_members" do before do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Group.new("wheel") @new_resource.members %w{lobster rage fist} @new_resource.append false @provider = Chef::Provider::Group::Gpasswd.new(@new_resource, @run_context) #@provider.stub!(:run_command).and_return(true) end describe "when determining the current group state" do before (:each) do @provider.load_current_resource @provider.define_resource_requirements end # Checking for required binaries is already done in the spec # for Chef::Provider::Group - no need to repeat it here. We'll # include only what's specific to this provider. it "should raise an error if the required binary /usr/bin/gpasswd doesn't exist" do File.stub!(:exists?).and_return(true) File.should_receive(:exists?).with("/usr/bin/gpasswd").and_return(false) lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Group) end it "shouldn't raise an error if the required binaries exist" do File.stub!(:exists?).and_return(true) lambda { @provider.process_resource_requirements }.should_not raise_error(Chef::Exceptions::Group) end end describe "after the group's current state is known" do before do @current_resource = @new_resource.dup @provider.current_resource = @new_resource end describe "when no group members are specified and append is not set" do before do @new_resource.append(false) @new_resource.members([]) end it "logs a message and sets group's members to 'none'" do Chef::Log.should_receive(:debug).with("group[wheel] setting group members to: none") @provider.should_receive(:shell_out!).with("gpasswd -M \"\" wheel") @provider.modify_group_members end end describe "when no group members are specified and append is set" do before do @new_resource.append(true) @new_resource.members([]) end it "logs a message and does not modify group membership" do Chef::Log.should_receive(:debug).with("group[wheel] not changing group members, the group has no members to add") @provider.should_not_receive(:shell_out!) @provider.modify_group_members end end describe "when the resource specifies group members" do it "should log an appropriate debug message" do Chef::Log.should_receive(:debug).with("group[wheel] setting group members to lobster, rage, fist") @provider.stub!(:shell_out!) @provider.modify_group_members end it "should run gpasswd with the members joined by ',' followed by the target group" do @provider.should_receive(:shell_out!).with("gpasswd -M lobster,rage,fist wheel") @provider.modify_group_members end it "should run gpasswd individually for each user when the append option is set" do @new_resource.append(true) @provider.should_receive(:shell_out!).with("gpasswd -a lobster wheel") @provider.should_receive(:shell_out!).with("gpasswd -a rage wheel") @provider.should_receive(:shell_out!).with("gpasswd -a fist wheel") @provider.modify_group_members end end end end chef-11.8.2/spec/unit/provider/group/groupadd_spec.rb0000644000004100000410000001470412254362222022611 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Group::Groupadd, "set_options" do before do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Group.new("aj") @new_resource.gid(50) @new_resource.members(["root", "aj"]) @new_resource.system false @new_resource.non_unique false @current_resource = Chef::Resource::Group.new("aj") @current_resource.gid(50) @current_resource.members(["root", "aj"]) @current_resource.system false @current_resource.non_unique false @provider = Chef::Provider::Group::Groupadd.new(@new_resource, @run_context) @provider.current_resource = @current_resource end field_list = { :gid => "-g" } field_list.each do |attribute, option| it "should check for differences in #{attribute.to_s} between the current and new resources" do @new_resource.should_receive(attribute) @current_resource.should_receive(attribute) @provider.set_options end it "should set the option for #{attribute} if the new resources #{attribute} is not null" do @new_resource.stub!(attribute).and_return("wowaweea") @provider.set_options.should eql(" #{option} '#{@new_resource.send(attribute)}' #{@new_resource.group_name}") end end it "should combine all the possible options" do match_string = "" field_list.sort{ |a,b| a[0] <=> b[0] }.each do |attribute, option| @new_resource.stub!(attribute).and_return("hola") match_string << " #{option} 'hola'" end match_string << " aj" @provider.set_options.should eql(match_string) end describe "when we want to create a system group" do it "should not set groupadd_options '-r' when system is false" do @new_resource.system(false) @provider.groupadd_options.should_not =~ /-r/ end it "should set groupadd -r if system is true" do @new_resource.system(true) @provider.groupadd_options.should == " -r" end end describe "when we want to create a non_unique gid group" do it "should not set groupadd_options '-o' when non_unique is false" do @new_resource.non_unique(false) @provider.groupadd_options.should_not =~ /-o/ end it "should set groupadd -o if non_unique is true" do @new_resource.non_unique(true) @provider.groupadd_options.should == " -o" end end end describe Chef::Provider::Group::Groupadd, "create_group" do before do @node = Chef::Node.new @new_resource = Chef::Resource::Group.new("aj") @provider = Chef::Provider::Group::Groupadd.new(@node, @new_resource) @provider.stub!(:run_command).and_return(true) @provider.stub!(:set_options).and_return(" monkey") @provider.stub!(:groupadd_options).and_return("") @provider.stub!(:modify_group_members).and_return(true) end it "should run groupadd with the return of set_options" do @provider.should_receive(:run_command).with({ :command => "groupadd monkey" }).and_return(true) @provider.create_group end it "should modify the group members" do @provider.should_receive(:modify_group_members).and_return(true) @provider.create_group end end describe Chef::Provider::Group::Groupadd do before do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Group.new("aj") @provider = Chef::Provider::Group::Groupadd.new(@new_resource, @run_context) @provider.stub!(:run_command).and_return(true) @provider.stub!(:set_options).and_return(" monkey") end describe "manage group" do it "should run groupmod with the return of set_options" do @provider.stub!(:modify_group_members).and_return(true) @provider.should_receive(:run_command).with({ :command => "groupmod monkey" }).and_return(true) @provider.manage_group end it "should modify the group members" do @provider.should_receive(:modify_group_members).and_return(true) @provider.manage_group end end describe "remove_group" do it "should run groupdel with the new resources group name" do @provider.should_receive(:run_command).with({ :command => "groupdel aj" }).and_return(true) @provider.remove_group end end describe "modify_group_members" do it "should raise an error when calling modify_group_members" do lambda { @provider.modify_group_members }.should raise_error(Chef::Exceptions::Group, "you must override modify_group_members in #{@provider.to_s}") end end describe "load_current_resource" do before do File.stub!(:exists?).and_return(false) @provider.define_resource_requirements end it "should raise an error if the required binary /usr/sbin/groupadd doesn't exist" do File.should_receive(:exists?).with("/usr/sbin/groupadd").and_return(false) lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Group) end it "should raise an error if the required binary /usr/sbin/groupmod doesn't exist" do File.should_receive(:exists?).with("/usr/sbin/groupadd").and_return(true) File.should_receive(:exists?).with("/usr/sbin/groupmod").and_return(false) lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Group) end it "should raise an error if the required binary /usr/sbin/groupdel doesn't exist" do File.should_receive(:exists?).with("/usr/sbin/groupadd").and_return(true) File.should_receive(:exists?).with("/usr/sbin/groupmod").and_return(true) File.should_receive(:exists?).with("/usr/sbin/groupdel").and_return(false) lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Group) end end end chef-11.8.2/spec/unit/provider/group/dscl_spec.rb0000644000004100000410000002507612254362222021735 0ustar www-datawww-data# # Author:: Dreamcat4 () # Copyright:: Copyright (c) 2009 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Group::Dscl do before do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Group.new("aj") @current_resource = Chef::Resource::Group.new("aj") @provider = Chef::Provider::Group::Dscl.new(@new_resource, @run_context) @provider.current_resource = @current_resource @status = mock("Process::Status", :exitstatus => 0) @pid = 2342 @stdin = StringIO.new @stdout = StringIO.new("\n") @stderr = StringIO.new("") @provider.stub!(:popen4).and_yield(@pid,@stdin,@stdout,@stderr).and_return(@status) end it "should run popen4 with the supplied array of arguments appended to the dscl command" do @provider.should_receive(:popen4).with("dscl . -cmd /Path arg1 arg2") @provider.dscl("cmd", "/Path", "arg1", "arg2") end it "should return an array of four elements - cmd, status, stdout, stderr" do dscl_retval = @provider.dscl("cmd /Path args") dscl_retval.should be_a_kind_of(Array) dscl_retval.should == ["dscl . -cmd /Path args",@status,"\n",""] end describe "safe_dscl" do before do @node = Chef::Node.new @provider = Chef::Provider::Group::Dscl.new(@node, @new_resource) @provider.stub!(:dscl).and_return(["cmd", @status, "stdout", "stderr"]) end it "should run dscl with the supplied cmd /Path args" do @provider.should_receive(:dscl).with("cmd /Path args") @provider.safe_dscl("cmd /Path args") end describe "with the dscl command returning a non zero exit status for a delete" do before do @status = mock("Process::Status", :exitstatus => 1) @provider.stub!(:dscl).and_return(["cmd", @status, "stdout", "stderr"]) end it "should return an empty string of standard output for a delete" do safe_dscl_retval = @provider.safe_dscl("delete /Path args") safe_dscl_retval.should be_a_kind_of(String) safe_dscl_retval.should == "" end it "should raise an exception for any other command" do lambda { @provider.safe_dscl("cmd /Path arguments") }.should raise_error(Chef::Exceptions::Group) end end describe "with the dscl command returning no such key" do before do @provider.stub!(:dscl).and_return(["cmd", @status, "No such key: ", "stderr"]) end it "should raise an exception" do lambda { @provider.safe_dscl("cmd /Path arguments") }.should raise_error(Chef::Exceptions::Group) end end describe "with the dscl command returning a zero exit status" do it "should return the third array element, the string of standard output" do safe_dscl_retval = @provider.safe_dscl("cmd /Path args") safe_dscl_retval.should be_a_kind_of(String) safe_dscl_retval.should == "stdout" end end end describe "get_free_gid" do before do @node = Chef::Node.new @provider = Chef::Provider::Group::Dscl.new(@node, @new_resource) @provider.stub!(:safe_dscl).and_return("\naj 200\njt 201\n") end it "should run safe_dscl with list /Groups gid" do @provider.should_receive(:safe_dscl).with("list /Groups gid") @provider.get_free_gid end it "should return the first unused gid number on or above 200" do @provider.get_free_gid.should equal(202) end it "should raise an exception when the search limit is exhausted" do search_limit = 1 lambda { @provider.get_free_gid(search_limit) }.should raise_error(RuntimeError) end end describe "gid_used?" do before do @node = Chef::Node.new @provider = Chef::Provider::Group::Dscl.new(@node, @new_resource) @provider.stub!(:safe_dscl).and_return("\naj 500\n") end it "should run safe_dscl with list /Groups gid" do @provider.should_receive(:safe_dscl).with("list /Groups gid") @provider.gid_used?(500) end it "should return true for a used gid number" do @provider.gid_used?(500).should be_true end it "should return false for an unused gid number" do @provider.gid_used?(501).should be_false end it "should return false if not given any valid gid number" do @provider.gid_used?(nil).should be_false end end describe "set_gid" do describe "with the new resource and a gid number which is already in use" do before do @provider.stub!(:gid_used?).and_return(true) end it "should raise an exception if the new resources gid is already in use" do lambda { @provider.set_gid }.should raise_error(Chef::Exceptions::Group) end end describe "with no gid number for the new resources" do it "should run get_free_gid and return a valid, unused gid number" do @provider.should_receive(:get_free_gid).and_return(501) @provider.set_gid end end describe "with blank gid number for the new resources" do before do @new_resource.instance_variable_set(:@gid, nil) @new_resource.stub!(:safe_dscl) end it "should run get_free_gid and return a valid, unused gid number" do @provider.should_receive(:get_free_gid).and_return(501) @provider.set_gid end end describe "with a valid gid number which is not already in use" do it "should run safe_dscl with create /Groups/group PrimaryGroupID gid" do @provider.stub(:get_free_gid).and_return(50) @provider.should_receive(:safe_dscl).with("list /Groups gid") @provider.should_receive(:safe_dscl).with("create /Groups/aj PrimaryGroupID 50").and_return(true) @provider.set_gid end end end describe "set_members" do describe "with existing members in the current resource and append set to false in the new resource" do before do @new_resource.stub!(:members).and_return([]) @new_resource.stub!(:append).and_return(false) @current_resource.stub!(:members).and_return(["all", "your", "base"]) end it "should log an appropriate message" do Chef::Log.should_receive(:debug).with("group[aj] removing group members all your base") @provider.set_members end it "should run safe_dscl with create /Groups/group GroupMembership to clear the Group's UID list" do @provider.should_receive(:safe_dscl).with("create /Groups/aj GroupMembers ''").and_return(true) @provider.should_receive(:safe_dscl).with("create /Groups/aj GroupMembership ''").and_return(true) @provider.set_members end end describe "with supplied members in the new resource" do before do @new_resource.members(["all", "your", "base"]) @current_resource.members([]) end it "should log an appropriate debug message" do Chef::Log.should_receive(:debug).with("group[aj] setting group members all, your, base") @provider.set_members end it "should run safe_dscl with append /Groups/group GroupMembership and group members all, your, base" do @provider.should_receive(:safe_dscl).with("create /Groups/aj GroupMembers ''").and_return(true) @provider.should_receive(:safe_dscl).with("append /Groups/aj GroupMembership all your base").and_return(true) @provider.should_receive(:safe_dscl).with("create /Groups/aj GroupMembership ''").and_return(true) @provider.set_members end end describe "with no members in the new resource" do before do @new_resource.append(true) @new_resource.members([]) end it "should not call safe_dscl" do @provider.should_not_receive(:safe_dscl) @provider.set_members end end end describe "when loading the current system state" do before (:each) do @provider.load_current_resource @provider.define_resource_requirements end it "raises an error if the required binary /usr/bin/dscl doesn't exist" do File.should_receive(:exists?).with("/usr/bin/dscl").and_return(false) lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Group) end it "doesn't raise an error if /usr/bin/dscl exists" do File.stub!(:exists?).and_return(true) lambda { @provider.process_resource_requirements }.should_not raise_error(Chef::Exceptions::Group) end end describe "when creating the group" do it "creates the group, password field, gid, and sets group membership" do @provider.should_receive(:set_gid).and_return(true) @provider.should_receive(:set_members).and_return(true) @provider.should_receive(:safe_dscl).with("create /Groups/aj Password '*'") @provider.should_receive(:safe_dscl).with("create /Groups/aj") @provider.create_group end end describe "managing the group" do it "should manage the group_name if it changed and the new resources group_name is not null" do @current_resource.group_name("oldval") @new_resource.group_name("newname") @provider.should_receive(:safe_dscl).with("create /Groups/newname") @provider.should_receive(:safe_dscl).with("create /Groups/newname Password '*'") @provider.manage_group end it "should manage the gid if it changed and the new resources gid is not null" do @current_resource.gid(23) @new_resource.gid(42) @provider.should_receive(:set_gid) @provider.manage_group end it "should manage the members if it changed and the new resources members is not null" do @current_resource.members(%{charlie root}) @new_resource.members(%{crab revenge}) @provider.should_receive(:set_members) @provider.manage_group end end describe "remove_group" do it "should run safe_dscl with delete /Groups/group and with the new resources group name" do @provider.should_receive(:safe_dscl).with("delete /Groups/aj").and_return(true) @provider.remove_group end end end chef-11.8.2/spec/unit/provider/group/groupmod_spec.rb0000644000004100000410000001220312254362222022630 0ustar www-datawww-data# # Author:: Dan Crosta () # Copyright:: Copyright (c) 2012 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Group::Groupmod do before do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Group.new("wheel") @new_resource.gid 123 @new_resource.members %w{lobster rage fist} @new_resource.append false @provider = Chef::Provider::Group::Groupmod.new(@new_resource, @run_context) end describe "manage_group" do describe "when determining the current group state" do it "should raise an error if the required binary /usr/sbin/group doesn't exist" do File.should_receive(:exists?).with("/usr/sbin/group").and_return(false) lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Group) end it "should raise an error if the required binary /usr/sbin/user doesn't exist" do File.should_receive(:exists?).with("/usr/sbin/group").and_return(true) File.should_receive(:exists?).with("/usr/sbin/user").and_return(false) lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Group) end it "shouldn't raise an error if the required binaries exist" do File.stub!(:exists?).and_return(true) lambda { @provider.load_current_resource }.should_not raise_error(Chef::Exceptions::Group) end end describe "after the group's current state is known" do before do @current_resource = @new_resource.dup @provider.current_resource = @current_resource end describe "when no group members are specified and append is not set" do before do @new_resource.append(false) @new_resource.members([]) end it "logs a message and sets group's members to 'none', then removes existing group members" do Chef::Log.should_receive(:debug).with("group[wheel] setting group members to: none") Chef::Log.should_receive(:debug).with("group[wheel] removing members lobster, rage, fist") @provider.should_receive(:shell_out!).with("group mod -n wheel_bak wheel") @provider.should_receive(:shell_out!).with("group add -g '123' -o wheel") @provider.should_receive(:shell_out!).with("group del wheel_bak") @provider.manage_group end end describe "when no group members are specified and append is set" do before do @new_resource.append(true) @new_resource.members([]) end it "logs a message and does not modify group membership" do Chef::Log.should_receive(:debug).with("group[wheel] not changing group members, the group has no members to add") @provider.should_not_receive(:shell_out!) @provider.manage_group end end describe "when removing some group members" do before do @new_resource.append(false) @new_resource.members(%w{ lobster }) end it "updates group membership correctly" do Chef::Log.stub!(:debug) @provider.should_receive(:shell_out!).with("group mod -n wheel_bak wheel") @provider.should_receive(:shell_out!).with("user mod -G wheel lobster") @provider.should_receive(:shell_out!).with("group add -g '123' -o wheel") @provider.should_receive(:shell_out!).with("group del wheel_bak") @provider.manage_group end end end end describe "create_group" do describe "when creating a new group" do before do @current_resource = Chef::Resource::Group.new("wheel") @provider.current_resource = @current_resource end it "should run a group add command and some user mod commands" do @provider.should_receive(:shell_out!).with("group add -g '123' wheel") @provider.should_receive(:shell_out!).with("user mod -G wheel lobster") @provider.should_receive(:shell_out!).with("user mod -G wheel rage") @provider.should_receive(:shell_out!).with("user mod -G wheel fist") @provider.create_group end end end describe "remove_group" do describe "when removing an existing group" do before do @current_resource = @new_resource.dup @provider.current_resource = @current_resource end it "should run a group del command" do @provider.should_receive(:shell_out!).with("group del wheel") @provider.remove_group end end end end chef-11.8.2/spec/unit/provider/group/pw_spec.rb0000644000004100000410000001160712254362222021431 0ustar www-datawww-data# # Author:: Stephen Haynes () # Copyright:: Copyright (c) 2009 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Group::Pw do before do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Group.new("wheel") @new_resource.gid 50 @new_resource.members [ "root", "aj"] @current_resource = Chef::Resource::Group.new("aj") @current_resource.gid 50 @current_resource.members [ "root", "aj"] @provider = Chef::Provider::Group::Pw.new(@new_resource, @run_context) @provider.current_resource = @current_resource end describe "when setting options for the pw command" do it "does not set the gid option if gids match or are unmanaged" do @provider.set_options.should == " wheel" end it "sets the option for gid if it is not nil" do @new_resource.gid(42) @provider.set_options.should eql(" wheel -g '42'") end end describe "when creating a group" do it "should run pw groupadd with the return of set_options and set_members_option" do @new_resource.gid(23) @provider.should_receive(:run_command).with({ :command => "pw groupadd wheel -g '23' -M root,aj" }).and_return(true) @provider.create_group end end describe "when managing the group" do it "should run pw groupmod with the return of set_options" do @new_resource.gid(42) @provider.should_receive(:run_command).with({ :command => "pw groupmod wheel -g '42' -M root,aj" }).and_return(true) @provider.manage_group end end describe "when removing the group" do it "should run pw groupdel with the new resources group name" do @provider.should_receive(:run_command).with({ :command => "pw groupdel wheel" }).and_return(true) @provider.remove_group end end describe "when setting group membership" do describe "with an empty members array in both the new and current resource" do before do @new_resource.stub!(:members).and_return([]) @current_resource.stub!(:members).and_return([]) end it "should log an appropriate message" do Chef::Log.should_receive(:debug).with("group[wheel] not changing group members, the group has no members") @provider.set_members_option end it "should set no options" do @provider.set_members_option.should eql("") end end describe "with an empty members array in the new resource and existing members in the current resource" do before do @new_resource.stub!(:members).and_return([]) @current_resource.stub!(:members).and_return(["all", "your", "base"]) end it "should log an appropriate message" do Chef::Log.should_receive(:debug).with("group[wheel] removing group members all, your, base") @provider.set_members_option end it "should set the -d option with the members joined by ','" do @provider.set_members_option.should eql(" -d all,your,base") end end describe "with supplied members array in the new resource and an empty members array in the current resource" do before do @new_resource.stub!(:members).and_return(["all", "your", "base"]) @current_resource.stub!(:members).and_return([]) end it "should log an appropriate debug message" do Chef::Log.should_receive(:debug).with("group[wheel] setting group members to all, your, base") @provider.set_members_option end it "should set the -M option with the members joined by ','" do @provider.set_members_option.should eql(" -M all,your,base") end end end describe"load_current_resource" do before (:each) do @provider.load_current_resource @provider.define_resource_requirements end it "should raise an error if the required binary /usr/sbin/pw doesn't exist" do File.should_receive(:exists?).with("/usr/sbin/pw").and_return(false) lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Group) end it "shouldn't raise an error if /usr/sbin/pw exists" do File.stub!(:exists?).and_return(true) lambda { @provider.process_resource_requirements }.should_not raise_error(Chef::Exceptions::Group) end end end chef-11.8.2/spec/unit/provider/ifconfig/0000755000004100000410000000000012254362222020067 5ustar www-datawww-datachef-11.8.2/spec/unit/provider/ifconfig/aix_spec.rb0000644000004100000410000001561712254362222022221 0ustar www-datawww-data# # Author:: Kaustubh Deorukhkar () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/exceptions' describe Chef::Provider::Ifconfig::Aix do before(:all) do @ifconfig_output = <<-IFCONFIG en1: flags=1e080863,480 inet 10.153.11.59 netmask 0xffff0000 broadcast 10.153.255.255 tcp_sendspace 262144 tcp_recvspace 262144 rfc1323 1 en0: flags=1e080863,480 metric 1 inet 172.29.174.58 netmask 0xffffc000 broadcast 172.29.191.255 tcp_sendspace 262144 tcp_recvspace 262144 rfc1323 1 lo0: flags=e08084b,c0 inet 127.0.0.1 netmask 0xff000000 broadcast 127.255.255.255 inet6 ::1%1/0 IFCONFIG end before(:each) do @node = Chef::Node.new @cookbook_collection = Chef::CookbookCollection.new([]) @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) @new_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context) @provider = Chef::Provider::Ifconfig::Aix.new(@new_resource, @run_context) end describe "#load_current_resource" do before do status = double("Status", :exitstatus => 0) @provider.should_receive(:popen4).with("ifconfig -a").and_yield(@pid,@stdin,StringIO.new(@ifconfig_output),@stderr).and_return(status) @new_resource.device "en0" end it "should load given interface with attributes." do current_resource = @provider.load_current_resource expect(current_resource.inet_addr).to eq("172.29.174.58") expect(current_resource.target).to eq(@new_resource.target) expect(current_resource.mask).to eq("255.255.192.0") expect(current_resource.bcast).to eq("172.29.191.255") expect(current_resource.metric).to eq("1") end end describe "#action_add" do it "should add an interface if it does not exist" do @new_resource.device "en10" @provider.stub!(:load_current_resource) do @provider.instance_variable_set("@status", double("Status", :exitstatus => 0)) @provider.instance_variable_set("@current_resource", Chef::Resource::Ifconfig.new("10.0.0.1", @run_context)) end command = "chdev -l #{@new_resource.device} -a netaddr=#{@new_resource.name}" @provider.should_receive(:run_command).with(:command => command) @provider.run_action(:add) @new_resource.should be_updated end it "should raise exception if metric attribute is set" do @new_resource.device "en0" @new_resource.metric "1" @provider.stub!(:load_current_resource) do @provider.instance_variable_set("@status", double("Status", :exitstatus => 0)) @provider.instance_variable_set("@current_resource", Chef::Resource::Ifconfig.new("10.0.0.1", @run_context)) end expect{@provider.run_action(:add)}.to raise_error(Chef::Exceptions::Ifconfig, "interface metric attribute cannot be set for :add action") end end describe "#action_enable" do it "should enable an interface if it does not exist" do @new_resource.device "en10" @provider.stub!(:load_current_resource) do @provider.instance_variable_set("@status", double("Status", :exitstatus => 0)) @provider.instance_variable_set("@current_resource", Chef::Resource::Ifconfig.new("10.0.0.1", @run_context)) end command = "ifconfig #{@new_resource.device} #{@new_resource.name}" @provider.should_receive(:run_command).with(:command => command) @provider.run_action(:enable) @new_resource.should be_updated end end describe "#action_disable" do it "should not disable an interface if it does not exist" do @new_resource.device "en10" @provider.stub!(:load_current_resource) do @provider.instance_variable_set("@status", double("Status", :exitstatus => 0)) @provider.instance_variable_set("@current_resource", Chef::Resource::Ifconfig.new("10.0.0.1", @run_context)) end @provider.should_not_receive(:run_command) @provider.run_action(:disable) @new_resource.should_not be_updated end context "interface exists" do before do @new_resource.device "en10" @provider.stub!(:load_current_resource) do @provider.instance_variable_set("@status", double("Status", :exitstatus => 0)) current_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context) current_resource.device @new_resource.device @provider.instance_variable_set("@current_resource", current_resource) end end it "should disable an interface if it exists" do command = "ifconfig #{@new_resource.device} down" @provider.should_receive(:run_command).with(:command => command) @provider.run_action(:disable) @new_resource.should be_updated end end end describe "#action_delete" do it "should not delete an interface if it does not exist" do @new_resource.device "en10" @provider.stub!(:load_current_resource) do @provider.instance_variable_set("@status", double("Status", :exitstatus => 0)) @provider.instance_variable_set("@current_resource", Chef::Resource::Ifconfig.new("10.0.0.1", @run_context)) end @provider.should_not_receive(:run_command) @provider.run_action(:delete) @new_resource.should_not be_updated end context "interface exists" do before do @new_resource.device "en10" @provider.stub!(:load_current_resource) do @provider.instance_variable_set("@status", double("Status", :exitstatus => 0)) current_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context) current_resource.device @new_resource.device @provider.instance_variable_set("@current_resource", current_resource) end end it "should delete an interface if it exists" do command = "chdev -l #{@new_resource.device} -a state=down" @provider.should_receive(:run_command).with(:command => command) @provider.run_action(:delete) @new_resource.should be_updated end end end end chef-11.8.2/spec/unit/provider/ifconfig/debian_spec.rb0000644000004100000410000000721212254362222022652 0ustar www-datawww-data# # Author:: Xabier de Zuazo (xabier@onddo.com) # Copyright:: Copyright (c) 2013 Onddo Labs, SL. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/exceptions' describe Chef::Provider::Ifconfig::Debian do before do @node = Chef::Node.new @cookbook_collection = Chef::CookbookCollection.new([]) @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) #This new_resource can be called anything --> it is not the same as in ifconfig.rb @new_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context) @new_resource.mask "255.255.254.0" @new_resource.metric "1" @new_resource.mtu "1500" @new_resource.device "eth0" @provider = Chef::Provider::Ifconfig::Debian.new(@new_resource, @run_context) @current_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context) status = mock("Status", :exitstatus => 0) @provider.instance_variable_set("@status", status) @provider.current_resource = @current_resource @provider.stub!(:load_current_resource) @provider.stub!(:run_command) @config_filename_ifaces = "/etc/network/interfaces" @config_filename_ifcfg = "/etc/network/interfaces.d/ifcfg-#{@new_resource.device}" end describe "generate_config for action_add" do before do @config_file_ifaces = StringIO.new @config_file_ifcfg = StringIO.new FileUtils.should_receive(:cp) File.should_receive(:new).with(@config_filename_ifaces).and_return(StringIO.new) File.should_receive(:open).with(@config_filename_ifaces, "w").and_yield(@config_file_ifaces) File.should_receive(:new).with(@config_filename_ifcfg, "w").and_return(@config_file_ifcfg) File.should_receive(:exist?).with(@config_filename_ifaces).and_return(true) end it "should create network-scripts directory" do File.should_receive(:directory?).with(File.dirname(@config_filename_ifcfg)).and_return(false) Dir.should_receive(:mkdir).with(File.dirname(@config_filename_ifcfg)) @provider.run_action(:add) end it "should write configure network-scripts directory" do File.should_receive(:directory?).with(File.dirname(@config_filename_ifcfg)).and_return(true) @provider.run_action(:add) @config_file_ifaces.string.should match(/^\s*source\s+\/etc\/network\/interfaces[.]d\/[*]\s*$/) end it "should write a network-script" do File.should_receive(:directory?).with(File.dirname(@config_filename_ifcfg)).and_return(true) @provider.run_action(:add) @config_file_ifcfg.string.should match(/^iface eth0 inet static\s*$/) @config_file_ifcfg.string.should match(/^\s+address 10\.0\.0\.1\s*$/) @config_file_ifcfg.string.should match(/^\s+netmask 255\.255\.254\.0\s*$/) end end describe "delete_config for action_delete" do it "should delete network-script if it exists" do @current_resource.device @new_resource.device File.should_receive(:exist?).with(@config_filename_ifcfg).and_return(true) FileUtils.should_receive(:rm_f).with(@config_filename_ifcfg, :verbose => false) @provider.run_action(:delete) end end end chef-11.8.2/spec/unit/provider/ifconfig/redhat_spec.rb0000644000004100000410000000536012254362222022701 0ustar www-datawww-data# # Author:: Xabier de Zuazo (xabier@onddo.com) # Copyright:: Copyright (c) 2013 Onddo Labs, SL. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/exceptions' describe Chef::Provider::Ifconfig::Redhat do before do @node = Chef::Node.new @cookbook_collection = Chef::CookbookCollection.new([]) @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) #This new_resource can be called anything --> it is not the same as in ifconfig.rb @new_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context) @new_resource.mask "255.255.254.0" @new_resource.metric "1" @new_resource.mtu "1500" @new_resource.device "eth0" @provider = Chef::Provider::Ifconfig::Redhat.new(@new_resource, @run_context) @current_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context) status = mock("Status", :exitstatus => 0) @provider.instance_variable_set("@status", status) @provider.current_resource = @current_resource end describe "generate_config for action_add" do it "should write network-script for centos" do @provider.stub!(:load_current_resource) @provider.stub!(:run_command) config_filename = "/etc/sysconfig/network-scripts/ifcfg-#{@new_resource.device}" config_file = StringIO.new File.should_receive(:new).with(config_filename, "w").and_return(config_file) @provider.run_action(:add) config_file.string.should match(/^\s*DEVICE=eth0\s*$/) config_file.string.should match(/^\s*IPADDR=10\.0\.0\.1\s*$/) config_file.string.should match(/^\s*NETMASK=255\.255\.254\.0\s*$/) end end describe "delete_config for action_delete" do it "should delete network-script if it exists for centos" do @current_resource.device @new_resource.device @provider.stub!(:load_current_resource) @provider.stub!(:run_command) config_filename = "/etc/sysconfig/network-scripts/ifcfg-#{@new_resource.device}" File.should_receive(:exist?).with(config_filename).and_return(true) FileUtils.should_receive(:rm_f).with(config_filename, :verbose => false) @provider.run_action(:delete) end end end chef-11.8.2/spec/unit/provider/execute_spec.rb0000644000004100000410000000645212254362222021313 0ustar www-datawww-data# # Author:: Prajakta Purohit () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper")) #require 'spec_helper' describe Chef::Provider::Execute do before do @node = Chef::Node.new @cookbook_collection = Chef::CookbookCollection.new([]) @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) @new_resource = Chef::Resource::Execute.new("foo_resource", @run_context) @new_resource.timeout 3600 @new_resource.returns 0 @new_resource.creates "/foo_resource" @provider = Chef::Provider::Execute.new(@new_resource, @run_context) @current_resource = Chef::Resource::Ifconfig.new("foo_resource", @run_context) @provider.current_resource = @current_resource Chef::Log.level = :info # FIXME: There should be a test for how STDOUT.tty? changes the live_stream option being passed STDOUT.stub!(:tty?).and_return(true) end it "should execute foo_resource" do @provider.stub!(:load_current_resource) opts = {} opts[:timeout] = @new_resource.timeout opts[:returns] = @new_resource.returns opts[:log_level] = :info opts[:log_tag] = @new_resource.to_s opts[:live_stream] = STDOUT @provider.should_receive(:shell_out!).with(@new_resource.command, opts) Chef::Log.should_not_receive(:warn) @provider.run_action(:run) @new_resource.should be_updated end it "should do nothing if the sentinel file exists" do @provider.stub!(:load_current_resource) File.should_receive(:exists?).with(@new_resource.creates).and_return(true) @provider.should_not_receive(:shell_out!) Chef::Log.should_not_receive(:warn) @provider.run_action(:run) @new_resource.should_not be_updated end it "should respect cwd options for 'creates'" do @new_resource.cwd "/tmp" @new_resource.creates "foo_resource" @provider.stub!(:load_current_resource) File.should_receive(:exists?).with(@new_resource.creates).and_return(false) File.should_receive(:exists?).with(File.join("/tmp", @new_resource.creates)).and_return(true) Chef::Log.should_not_receive(:warn) @provider.should_not_receive(:shell_out!) @provider.run_action(:run) @new_resource.should_not be_updated end it "should warn if user specified relative path without cwd" do @new_resource.creates "foo_resource" @provider.stub!(:load_current_resource) Chef::Log.should_receive(:warn).with(/relative path/) File.should_receive(:exists?).with(@new_resource.creates).and_return(true) @provider.should_not_receive(:shell_out!) @provider.run_action(:run) @new_resource.should_not be_updated end end chef-11.8.2/spec/unit/provider/mount_spec.rb0000644000004100000410000001454212254362222021012 0ustar www-datawww-data# # Author:: Joshua Timberman () # Copyright:: Copyright (c) 2008 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Mount do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Mount.new('/tmp/foo') @new_resource.device "/dev/sdz1" @new_resource.name "/tmp/foo" @new_resource.mount_point "/tmp/foo" @new_resource.fstype "ext3" @current_resource = Chef::Resource::Mount.new('/tmp/foo') @current_resource.device "/dev/sdz1" @current_resource.name "/tmp/foo" @current_resource.mount_point "/tmp/foo" @current_resource.fstype "ext3" @provider = Chef::Provider::Mount.new(@new_resource, @run_context) @provider.current_resource = @current_resource end describe "when the target state is a mounted filesystem" do it "should mount the filesystem if it isn't mounted" do @current_resource.stub!(:mounted).and_return(false) @provider.should_receive(:mount_fs).with.and_return(true) @provider.run_action(:mount) @new_resource.should be_updated_by_last_action end it "should not mount the filesystem if it is mounted" do @current_resource.stub!(:mounted).and_return(true) @provider.should_not_receive(:mount_fs) @provider.run_action(:mount) @new_resource.should_not be_updated_by_last_action end end describe "when the target state is an unmounted filesystem" do it "should umount the filesystem if it is mounted" do @current_resource.stub!(:mounted).and_return(true) @provider.should_receive(:umount_fs).with.and_return(true) @provider.run_action(:umount) @new_resource.should be_updated_by_last_action end it "should not umount the filesystem if it is not mounted" do @current_resource.stub!(:mounted).and_return(false) @provider.should_not_receive(:umount_fs) @provider.run_action(:umount) @new_resource.should_not be_updated_by_last_action end end describe "when the filesystem should be remounted and the resource supports remounting" do before do @new_resource.supports[:remount] = true end it "should remount the filesystem if it is mounted" do @current_resource.stub!(:mounted).and_return(true) @provider.should_receive(:remount_fs).and_return(true) @provider.run_action(:remount) @new_resource.should be_updated_by_last_action end it "should not remount the filesystem if it is not mounted" do @current_resource.stub!(:mounted).and_return(false) @provider.should_not_receive(:remount_fs) @provider.run_action(:remount) @new_resource.should_not be_updated_by_last_action end end describe "when the filesystem should be remounted and the resource does not support remounting" do before do @new_resource.supports[:remount] = false end it "should fail to remount the filesystem" do @provider.should_not_receive(:remount_fs) lambda {@provider.run_action(:remount)}.should raise_error(Chef::Exceptions::UnsupportedAction) @new_resource.should_not be_updated_by_last_action end end describe "when enabling the filesystem to be mounted" do it "should enable the mount if it isn't enable" do @current_resource.stub!(:enabled).and_return(false) @provider.should_not_receive(:mount_options_unchanged?) @provider.should_receive(:enable_fs).and_return(true) @provider.run_action(:enable) @new_resource.should be_updated_by_last_action end it "should enable the mount if it is enabled and mount options have changed" do @current_resource.stub!(:enabled).and_return(true) @provider.should_receive(:mount_options_unchanged?).and_return(false) @provider.should_receive(:enable_fs).and_return(true) @provider.run_action(:enable) @new_resource.should be_updated_by_last_action end it "should not enable the mount if it is enabled and mount options have not changed" do @current_resource.stub!(:enabled).and_return(true) @provider.should_receive(:mount_options_unchanged?).and_return(true) @provider.should_not_receive(:enable_fs).and_return(true) @provider.run_action(:enable) @new_resource.should_not be_updated_by_last_action end end describe "when the target state is to disable the mount" do it "should disable the mount if it is enabled" do @current_resource.stub!(:enabled).and_return(true) @provider.should_receive(:disable_fs).with.and_return(true) @provider.run_action(:disable) @new_resource.should be_updated_by_last_action end it "should not disable the mount if it isn't enabled" do @current_resource.stub!(:enabled).and_return(false) @provider.should_not_receive(:disable_fs) @provider.run_action(:disable) @new_resource.should_not be_updated_by_last_action end end it "should delegates the mount implementation to subclasses" do lambda { @provider.mount_fs }.should raise_error(Chef::Exceptions::UnsupportedAction) end it "should delegates the umount implementation to subclasses" do lambda { @provider.umount_fs }.should raise_error(Chef::Exceptions::UnsupportedAction) end it "should delegates the remount implementation to subclasses" do lambda { @provider.remount_fs }.should raise_error(Chef::Exceptions::UnsupportedAction) end it "should delegates the enable implementation to subclasses" do lambda { @provider.enable_fs }.should raise_error(Chef::Exceptions::UnsupportedAction) end it "should delegates the disable implementation to subclasses" do lambda { @provider.disable_fs }.should raise_error(Chef::Exceptions::UnsupportedAction) end end chef-11.8.2/spec/unit/provider/env_spec.rb0000644000004100000410000001672612254362222020446 0ustar www-datawww-data# # Author:: Doug MacEachern () # Copyright:: Copyright (c) 2010 VMware, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Env do before do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Env.new("FOO") @new_resource.value("bar") @provider = Chef::Provider::Env.new(@new_resource, @run_context) end it "assumes the key_name exists by default" do @provider.key_exists.should be_true end describe "when loading the current status" do before do #@current_resource = @new_resource.clone #Chef::Resource::Env.stub!(:new).and_return(@current_resource) @provider.current_resource = @current_resource @provider.stub!(:env_value).with("FOO").and_return("bar") @provider.stub!(:env_key_exists).and_return(true) end it "should create a current resource with the same name as the new resource" do @provider.load_current_resource @provider.new_resource.name.should == "FOO" end it "should set the key_name to the key name of the new resource" do @provider.load_current_resource @provider.current_resource.key_name.should == "FOO" end it "should check if the key_name exists" do @provider.should_receive(:env_key_exists).with("FOO").and_return(true) @provider.load_current_resource @provider.key_exists.should be_true end it "should flip the value of exists if the key does not exist" do @provider.should_receive(:env_key_exists).with("FOO").and_return(false) @provider.load_current_resource @provider.key_exists.should be_false end it "should return the current resource" do @provider.load_current_resource.should be_a_kind_of(Chef::Resource::Env) end end describe "action_create" do before do @provider.key_exists = false @provider.stub!(:create_env).and_return(true) @provider.stub!(:modify_env).and_return(true) end it "should call create_env if the key does not exist" do @provider.should_receive(:create_env).and_return(true) @provider.action_create end it "should set the new_resources updated flag when it creates the key" do @provider.action_create @new_resource.should be_updated end it "should check to see if the values are the same if the key exists" do @provider.key_exists = true @provider.should_receive(:compare_value).and_return(false) @provider.action_create end it "should call modify_env if the key exists and values are not equal" do @provider.key_exists = true @provider.stub!(:compare_value).and_return(true) @provider.should_receive(:modify_env).and_return(true) @provider.action_create end it "should set the new_resources updated flag when it updates an existing value" do @provider.key_exists = true @provider.stub!(:compare_value).and_return(true) @provider.stub!(:modify_env).and_return(true) @provider.action_create @new_resource.should be_updated end end describe "action_delete" do before(:each) do @provider.current_resource = @current_resource @provider.key_exists = false @provider.stub!(:delete_element).and_return(false) @provider.stub!(:delete_env).and_return(true) end it "should not call delete_env if the key does not exist" do @provider.should_not_receive(:delete_env) @provider.action_delete end it "should not call delete_element if the key does not exist" do @provider.should_not_receive(:delete_element) @provider.action_delete end it "should call delete_env if the key exists" do @provider.key_exists = true @provider.should_receive(:delete_env) @provider.action_delete end it "should set the new_resources updated flag to true if the key is deleted" do @provider.key_exists = true @provider.action_delete @new_resource.should be_updated end end describe "action_modify" do before(:each) do @provider.current_resource = @current_resource @provider.key_exists = true @provider.stub!(:modify_env).and_return(true) end it "should call modify_group if the key exists and values are not equal" do @provider.should_receive(:compare_value).and_return(true) @provider.should_receive(:modify_env).and_return(true) @provider.action_modify end it "should set the new resources updated flag to true if modify_env is called" do @provider.stub!(:compare_value).and_return(true) @provider.stub!(:modify_env).and_return(true) @provider.action_modify @new_resource.should be_updated end it "should not call modify_env if the key exists but the values are equal" do @provider.should_receive(:compare_value).and_return(false) @provider.should_not_receive(:modify_env) @provider.action_modify end it "should raise a Chef::Exceptions::Env if the key doesn't exist" do @provider.key_exists = false lambda { @provider.action_modify }.should raise_error(Chef::Exceptions::Env) end end describe "delete_element" do before(:each) do @current_resource = Chef::Resource::Env.new("FOO") @new_resource.delim ";" @new_resource.value "C:/bar/bin" @current_resource.value "C:/foo/bin;C:/bar/bin" @provider.current_resource = @current_resource end it "should return true if the element is not found" do @new_resource.stub!(:value).and_return("C:/baz/bin") @provider.delete_element.should eql(true) end it "should return false if the delim not defined" do @new_resource.stub!(:delim).and_return(nil) @provider.delete_element.should eql(false) end it "should return true if the element is deleted" do @new_resource.value("C:/foo/bin") @provider.should_receive(:create_env) @provider.delete_element.should eql(true) @new_resource.should be_updated end end describe "compare_value" do before(:each) do @new_resource.value("C:/bar") @current_resource = @new_resource.clone @provider.current_resource = @current_resource end it "should return false if the values are equal" do @provider.compare_value.should be_false end it "should return true if the values not are equal" do @new_resource.value("C:/elsewhere") @provider.compare_value.should be_true end it "should return false if the current value contains the element" do @new_resource.delim(";") @current_resource.value("C:/bar;C:/foo;C:/baz") @provider.compare_value.should be_false end it "should return true if the current value does not contain the element" do @new_resource.delim(";") @current_resource.value("C:/biz;C:/foo/bin;C:/baz") @provider.compare_value.should be_true end end end chef-11.8.2/spec/unit/provider/script_spec.rb0000644000004100000410000000600512254362222021147 0ustar www-datawww-data# # Author:: Adam Jacob (adam@opscode.com) # Copyright:: Copyright (c) 2009 Opscode # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Script, "action_run" do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Script.new('run some perl code') @new_resource.code "$| = 1; print 'i like beans'" @new_resource.interpreter 'perl' @provider = Chef::Provider::Script.new(@new_resource, @run_context) @script_file = StringIO.new @script_file.stub!(:path).and_return('/tmp/the_script_file') @provider.stub!(:shell_out!).and_return(true) end it "creates a temporary file to store the script" do @provider.script_file.should be_an_instance_of(Tempfile) end it "unlinks the tempfile when finished" do tempfile_path = @provider.script_file.path @provider.unlink_script_file File.exist?(tempfile_path).should be_false end it "sets the owner and group for the script file" do @new_resource.user 'toor' @new_resource.group 'wheel' @provider.stub!(:script_file).and_return(@script_file) FileUtils.should_receive(:chown).with('toor', 'wheel', "/tmp/the_script_file") @provider.set_owner_and_group end context "with the script file set to the correct owner and group" do before do @provider.stub!(:set_owner_and_group) @provider.stub!(:script_file).and_return(@script_file) end describe "when writing the script to the file" do it "should put the contents of the script in the temp file" do @provider.action_run @script_file.rewind @script_file.string.should == "$| = 1; print 'i like beans'\n" end it "closes before executing the script and unlinks it when finished" do @provider.action_run @script_file.should be_closed end end describe "when running the script" do it 'should set the command to "interpreter" "tempfile"' do @provider.action_run @new_resource.command.should == '"perl" "/tmp/the_script_file"' end describe "with flags set on the resource" do before do @new_resource.flags '-f' end it "should set the command to 'interpreter flags tempfile'" do @provider.action_run @new_resource.command.should == '"perl" -f "/tmp/the_script_file"' end end end end end chef-11.8.2/spec/unit/provider/ifconfig_spec.rb0000644000004100000410000001463412254362222021436 0ustar www-datawww-data# # Author:: Prajakta Purohit (prajakta@opscode.com) # Copyright:: Copyright (c) 2008 Opscode Inc. # License:: Apache License, Version 2.0 # # 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. # #require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper")) require 'spec_helper' require 'chef/exceptions' describe Chef::Provider::Ifconfig do before do @node = Chef::Node.new @cookbook_collection = Chef::CookbookCollection.new([]) @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) #This new_resource can be called anything --> it is not the same as in ifconfig.rb @new_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context) @new_resource.mask "255.255.254.0" @new_resource.metric "1" @new_resource.mtu "1500" @new_resource.device "eth0" @provider = Chef::Provider::Ifconfig.new(@new_resource, @run_context) @current_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context) status = mock("Status", :exitstatus => 0) @provider.instance_variable_set("@status", status) @provider.current_resource = @current_resource end describe Chef::Provider::Ifconfig, "load_current_resource" do before do status = mock("Status", :exitstatus => 1) @provider.should_receive(:popen4).and_return status @provider.load_current_resource end it "should track state of ifconfig failure." do @provider.instance_variable_get("@status").exitstatus.should_not == 0 end it "should thrown an exception when ifconfig fails" do @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error Chef::Exceptions::Ifconfig end end describe Chef::Provider::Ifconfig, "action_add" do it "should add an interface if it does not exist" do #@provider.stub!(:run_command).and_return(true) @provider.stub!(:load_current_resource) @current_resource.inet_addr nil command = "ifconfig eth0 10.0.0.1 netmask 255.255.254.0 metric 1 mtu 1500" @provider.should_receive(:run_command).with(:command => command) @provider.should_receive(:generate_config) @provider.run_action(:add) @new_resource.should be_updated end it "should not add an interface if it already exists" do @provider.stub!(:load_current_resource) @provider.should_not_receive(:run_command) @current_resource.inet_addr "10.0.0.1" @provider.should_not_receive(:generate_config) @provider.run_action(:add) @new_resource.should_not be_updated end #We are not testing this case with the assumption that anyone writing the cookbook would not make a typo == lo #it "should add a blank command if the #{@new_resource.device} == lo" do #end end describe Chef::Provider::Ifconfig, "action_enable" do it "should enable interface if does not exist" do @provider.stub!(:load_current_resource) @current_resource.inet_addr nil command = "ifconfig eth0 10.0.0.1 netmask 255.255.254.0 metric 1 mtu 1500" @provider.should_receive(:run_command).with(:command => command) @provider.should_not_receive(:generate_config) @provider.run_action(:enable) @new_resource.should be_updated end it "should not enable interface if it already exists" do @provider.stub!(:load_current_resource) @provider.should_not_receive(:run_command) @current_resource.inet_addr "10.0.0.1" @provider.should_not_receive(:generate_config) @provider.run_action(:enable) @new_resource.should_not be_updated end end describe Chef::Provider::Ifconfig, "action_delete" do it "should delete interface if it exists" do @provider.stub!(:load_current_resource) @current_resource.device "eth0" command = "ifconfig #{@new_resource.device} down" @provider.should_receive(:run_command).with(:command => command) @provider.should_receive(:delete_config) @provider.run_action(:delete) @new_resource.should be_updated end it "should not delete interface if it does not exist" do @provider.stub!(:load_current_resource) @provider.should_not_receive(:run_command) @provider.should_not_receive(:delete_config) @provider.run_action(:delete) @new_resource.should_not be_updated end end describe Chef::Provider::Ifconfig, "action_disable" do it "should disable interface if it exists" do @provider.stub!(:load_current_resource) @current_resource.device "eth0" command = "ifconfig #{@new_resource.device} down" @provider.should_receive(:run_command).with(:command => command) @provider.should_not_receive(:delete_config) @provider.run_action(:disable) @new_resource.should be_updated end it "should not delete interface if it does not exist" do @provider.stub!(:load_current_resource) @provider.should_not_receive(:run_command) @provider.should_not_receive(:delete_config) @provider.run_action(:disable) @new_resource.should_not be_updated end end describe Chef::Provider::Ifconfig, "action_delete" do it "should delete interface of it exists" do @provider.stub!(:load_current_resource) @current_resource.device "eth0" command = "ifconfig #{@new_resource.device} down" @provider.should_receive(:run_command).with(:command => command) @provider.should_receive(:delete_config) @provider.run_action(:delete) @new_resource.should be_updated end it "should not delete interface if it does not exist" do # This is so that our fake values do not get overwritten @provider.stub!(:load_current_resource) # This is so that nothing actually runs @provider.should_not_receive(:run_command) @provider.should_not_receive(:delete_config) @provider.run_action(:delete) @new_resource.should_not be_updated end end end chef-11.8.2/spec/unit/provider/package_spec.rb0000644000004100000410000004104212254362222021236 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Package do before do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Package.new('emacs') @current_resource = Chef::Resource::Package.new('emacs') @provider = Chef::Provider::Package.new(@new_resource, @run_context) @provider.current_resource = @current_resource @provider.candidate_version = "1.0" end describe "when installing a package" do before(:each) do @provider.current_resource = @current_resource @provider.stub!(:install_package).and_return(true) end it "should raise a Chef::Exceptions::Package if no version is specified, and no candidate is available" do @provider.candidate_version = nil lambda { @provider.run_action(:install) }.should raise_error(Chef::Exceptions::Package) end it "should call preseed_package if a response_file is given" do @new_resource.response_file("foo") @provider.should_receive(:get_preseed_file).with( @new_resource.name, @provider.candidate_version ).and_return("/var/cache/preseed-test") @provider.should_receive(:preseed_package).with( "/var/cache/preseed-test" ).and_return(true) @provider.run_action(:install) end it "should not call preseed_package if a response_file is not given" do @provider.should_not_receive(:preseed_package) @provider.run_action(:install) end it "should install the package at the candidate_version if it is not already installed" do @provider.should_receive(:install_package).with( @new_resource.name, @provider.candidate_version ).and_return(true) @provider.run_action(:install) @new_resource.should be_updated_by_last_action end it "should install the package at the version specified if it is not already installed" do @new_resource.version("1.0") @provider.should_receive(:install_package).with( @new_resource.name, @new_resource.version ).and_return(true) @provider.run_action(:install) @new_resource.should be_updated_by_last_action end it "should install the package at the version specified if a different version is installed" do @new_resource.version("1.0") @current_resource.stub!(:version).and_return("0.99") @provider.should_receive(:install_package).with( @new_resource.name, @new_resource.version ).and_return(true) @provider.run_action(:install) @new_resource.should be_updated_by_last_action end it "should not install the package if it is already installed and no version is specified" do @current_resource.version("1.0") @provider.should_not_receive(:install_package) @provider.run_action(:install) @new_resource.should_not be_updated_by_last_action end it "should not install the package if it is already installed at the version specified" do @current_resource.version("1.0") @new_resource.version("1.0") @provider.should_not_receive(:install_package) @provider.run_action(:install) @new_resource.should_not be_updated_by_last_action end it "should call the candidate_version accessor only once if the package is already installed and no version is specified" do @current_resource.version("1.0") @provider.stub!(:candidate_version).and_return("1.0") @provider.run_action(:install) end it "should call the candidate_version accessor only once if the package is already installed at the version specified" do @current_resource.version("1.0") @new_resource.version("1.0") @provider.run_action(:install) end it "should set the resource to updated if it installs the package" do @provider.run_action(:install) @new_resource.should be_updated end end describe "when upgrading the package" do before(:each) do @provider.stub!(:upgrade_package).and_return(true) end it "should upgrade the package if the current version is not the candidate version" do @provider.should_receive(:upgrade_package).with( @new_resource.name, @provider.candidate_version ).and_return(true) @provider.run_action(:upgrade) @new_resource.should be_updated_by_last_action end it "should set the resource to updated if it installs the package" do @provider.run_action(:upgrade) @new_resource.should be_updated end it "should not install the package if the current version is the candidate version" do @current_resource.version "1.0" @provider.should_not_receive(:upgrade_package) @provider.run_action(:upgrade) @new_resource.should_not be_updated_by_last_action end it "should print the word 'uninstalled' if there was no original version" do @current_resource.stub!(:version).and_return(nil) Chef::Log.should_receive(:info).with("package[emacs] upgraded from uninstalled to 1.0") @provider.run_action(:upgrade) @new_resource.should be_updated_by_last_action end it "should raise a Chef::Exceptions::Package if current version and candidate are nil" do @current_resource.stub!(:version).and_return(nil) @provider.candidate_version = nil lambda { @provider.run_action(:upgrade) }.should raise_error(Chef::Exceptions::Package) end it "should not install the package if candidate version is nil" do @current_resource.version "1.0" @provider.candidate_version = nil @provider.should_not_receive(:upgrade_package) @provider.run_action(:upgrade) @new_resource.should_not be_updated_by_last_action end end describe "When removing the package" do before(:each) do @provider.stub!(:remove_package).and_return(true) @current_resource.version '1.4.2' end it "should remove the package if it is installed" do @provider.should be_removing_package @provider.should_receive(:remove_package).with('emacs', nil) @provider.run_action(:remove) @new_resource.should be_updated @new_resource.should be_updated_by_last_action end it "should remove the package at a specific version if it is installed at that version" do @new_resource.version "1.4.2" @provider.should be_removing_package @provider.should_receive(:remove_package).with('emacs', '1.4.2') @provider.run_action(:remove) @new_resource.should be_updated_by_last_action end it "should not remove the package at a specific version if it is not installed at that version" do @new_resource.version "1.0" @provider.should_not be_removing_package @provider.should_not_receive(:remove_package) @provider.run_action(:remove) @new_resource.should_not be_updated_by_last_action end it "should not remove the package if it is not installed" do @provider.should_not_receive(:remove_package) @current_resource.stub!(:version).and_return(nil) @provider.run_action(:remove) @new_resource.should_not be_updated_by_last_action end it "should set the resource to updated if it removes the package" do @provider.run_action(:remove) @new_resource.should be_updated end end describe "When purging the package" do before(:each) do @provider.stub!(:purge_package).and_return(true) @current_resource.version '1.4.2' end it "should purge the package if it is installed" do @provider.should be_removing_package @provider.should_receive(:purge_package).with('emacs', nil) @provider.run_action(:purge) @new_resource.should be_updated @new_resource.should be_updated_by_last_action end it "should purge the package at a specific version if it is installed at that version" do @new_resource.version "1.4.2" @provider.should be_removing_package @provider.should_receive(:purge_package).with('emacs', '1.4.2') @provider.run_action(:purge) @new_resource.should be_updated_by_last_action end it "should not purge the package at a specific version if it is not installed at that version" do @new_resource.version "1.0" @provider.should_not be_removing_package @provider.should_not_receive(:purge_package) @provider.run_action(:purge) @new_resource.should_not be_updated_by_last_action end it "should not purge the package if it is not installed" do @current_resource.instance_variable_set(:@version, nil) @provider.should_not be_removing_package @provider.should_not_receive(:purge_package) @provider.run_action(:purge) @new_resource.should_not be_updated_by_last_action end it "should set the resource to updated if it purges the package" do @provider.run_action(:purge) @new_resource.should be_updated end end describe "when reconfiguring the package" do before(:each) do @provider.stub!(:reconfig_package).and_return(true) end it "should info log, reconfigure the package and update the resource" do @current_resource.stub!(:version).and_return('1.0') @new_resource.stub!(:response_file).and_return(true) @provider.should_receive(:get_preseed_file).and_return('/var/cache/preseed-test') @provider.stub!(:preseed_package).and_return(true) @provider.stub!(:reconfig_package).and_return(true) Chef::Log.should_receive(:info).with("package[emacs] reconfigured") @provider.should_receive(:reconfig_package) @provider.run_action(:reconfig) @new_resource.should be_updated @new_resource.should be_updated_by_last_action end it "should debug log and not reconfigure the package if the package is not installed" do @current_resource.stub!(:version).and_return(nil) Chef::Log.should_receive(:debug).with("package[emacs] is NOT installed - nothing to do") @provider.should_not_receive(:reconfig_package) @provider.run_action(:reconfig) @new_resource.should_not be_updated_by_last_action end it "should debug log and not reconfigure the package if no response_file is given" do @current_resource.stub!(:version).and_return('1.0') @new_resource.stub!(:response_file).and_return(nil) Chef::Log.should_receive(:debug).with("package[emacs] no response_file provided - nothing to do") @provider.should_not_receive(:reconfig_package) @provider.run_action(:reconfig) @new_resource.should_not be_updated_by_last_action end it "should debug log and not reconfigure the package if the response_file has not changed" do @current_resource.stub!(:version).and_return('1.0') @new_resource.stub!(:response_file).and_return(true) @provider.should_receive(:get_preseed_file).and_return(false) @provider.stub!(:preseed_package).and_return(false) Chef::Log.should_receive(:debug).with("package[emacs] preseeding has not changed - nothing to do") @provider.should_not_receive(:reconfig_package) @provider.run_action(:reconfig) @new_resource.should_not be_updated_by_last_action end end describe "when running commands to be implemented by subclasses" do it "should raises UnsupportedAction for install" do lambda { @provider.install_package('emacs', '1.4.2') }.should raise_error(Chef::Exceptions::UnsupportedAction) end it "should raises UnsupportedAction for upgrade" do lambda { @provider.upgrade_package('emacs', '1.4.2') }.should raise_error(Chef::Exceptions::UnsupportedAction) end it "should raises UnsupportedAction for remove" do lambda { @provider.remove_package('emacs', '1.4.2') }.should raise_error(Chef::Exceptions::UnsupportedAction) end it "should raises UnsupportedAction for purge" do lambda { @provider.purge_package('emacs', '1.4.2') }.should raise_error(Chef::Exceptions::UnsupportedAction) end it "should raise UnsupportedAction for preseed_package" do preseed_file = "/tmp/sun-jdk-package-preseed-file.seed" lambda { @provider.preseed_package(preseed_file) }.should raise_error(Chef::Exceptions::UnsupportedAction) end it "should raise UnsupportedAction for reconfig" do lambda { @provider.reconfig_package('emacs', '1.4.2') }.should raise_error(Chef::Exceptions::UnsupportedAction) end end describe "when given a response file" do before(:each) do @cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, @cookbook_repo) } @node = Chef::Node.new cl = Chef::CookbookLoader.new(@cookbook_repo) cl.load_cookbooks @cookbook_collection = Chef::CookbookCollection.new(cl) @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) @provider.run_context = @run_context @node.automatic_attrs[:platform] = 'PLATFORM: just testing' @node.automatic_attrs[:platform_version] = 'PLATFORM VERSION: just testing' @new_resource.response_file('java.response') @new_resource.cookbook_name = 'java' end describe "creating the cookbook file resource to fetch the response file" do before do Chef::FileCache.should_receive(:create_cache_path).with('preseed/java').and_return("/tmp/preseed/java") end it "sets the preseed resource's runcontext to its own run context" do Chef::FileCache.stub!(:create_cache_path).and_return("/tmp/preseed/java") @provider.preseed_resource('java', '6').run_context.should_not be_nil @provider.preseed_resource('java', '6').run_context.should equal(@provider.run_context) end it "should set the cookbook name of the remote file to the new resources cookbook name" do @provider.preseed_resource('java', '6').cookbook_name.should == 'java' end it "should set remote files source to the new resources response file" do @provider.preseed_resource('java', '6').source.should == 'java.response' end it "should never back up the cached response file" do @provider.preseed_resource('java', '6').backup.should be_false end it "sets the install path of the resource to $file_cache/$cookbook/$pkg_name-$pkg_version.seed" do @provider.preseed_resource('java', '6').path.should == '/tmp/preseed/java/java-6.seed' end end describe "when installing the preseed file to the cache location" do before do @node.automatic_attrs[:platform] = :just_testing @node.automatic_attrs[:platform_version] = :just_testing @response_file_destination = Dir.tmpdir + '/preseed--java--java-6.seed' @response_file_resource = Chef::Resource::CookbookFile.new(@response_file_destination, @run_context) @response_file_resource.cookbook_name = 'java' @response_file_resource.backup(false) @response_file_resource.source('java.response') @provider.should_receive(:preseed_resource).with('java', '6').and_return(@response_file_resource) end after do FileUtils.rm(@response_file_destination) if ::File.exist?(@response_file_destination) end it "creates the preseed file in the cache" do @response_file_resource.should_receive(:run_action).with(:create) @provider.get_preseed_file("java", "6") end it "returns the path to the response file if the response file was updated" do @provider.get_preseed_file("java", "6").should == @response_file_destination end it "should return false if the response file has not been updated" do @response_file_resource.updated_by_last_action(false) @response_file_resource.should_not be_updated_by_last_action # don't let the response_file_resource set updated to true @response_file_resource.should_receive(:run_action).with(:create) @provider.get_preseed_file("java", "6").should be(false) end end end end chef-11.8.2/spec/unit/provider/template/0000755000004100000410000000000012254362222020116 5ustar www-datawww-datachef-11.8.2/spec/unit/provider/template/content_spec.rb0000644000004100000410000000560012254362222023130 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Template::Content do let(:new_resource) do mock("Chef::Resource::Template (new)", :cookbook_name => 'openldap', :source => 'openldap_stuff.conf.erb', :local => false, :cookbook => nil, :variables => {}, :inline_helper_blocks => {}, :inline_helper_modules => [], :helper_modules => []) end let(:rendered_file_location) { Dir.tmpdir + '/openldap_stuff.conf' } let(:run_context) do cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_repo) } cl = Chef::CookbookLoader.new(cookbook_repo) cl.load_cookbooks cookbook_collection = Chef::CookbookCollection.new(cl) node = Chef::Node.new mock("Chef::Resource::RunContext", :node => node, :cookbook_collection => cookbook_collection) end let(:content) do current_resource = mock("Chef::Resource::Template (current)") Chef::Provider::Template::Content.new(new_resource, current_resource, run_context) end after do FileUtils.rm(rendered_file_location) if ::File.exist?(rendered_file_location) end it "finds the template file in the cookbook cache if it isn't local" do content.template_location.should == CHEF_SPEC_DATA + '/cookbooks/openldap/templates/default/openldap_stuff.conf.erb' end it "finds the template file locally if it is local" do new_resource.stub!(:local).and_return(true) new_resource.stub!(:source).and_return('/tmp/its_on_disk.erb') content.template_location.should == '/tmp/its_on_disk.erb' end it "should use the cookbook name if defined in the template resource" do new_resource.stub!(:cookbook_name).and_return('apache2') new_resource.stub!(:cookbook).and_return('openldap') new_resource.stub!(:source).and_return("test.erb") content.template_location.should == CHEF_SPEC_DATA + '/cookbooks/openldap/templates/default/test.erb' end it "creates the template with the rendered content" do run_context.node.normal[:slappiness] = "a warm gun" IO.read(content.tempfile.path).should == "slappiness is a warm gun" end end chef-11.8.2/spec/unit/provider/cookbook_file_spec.rb0000644000004100000410000000335612254362222022456 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2009-2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'ostruct' require 'support/shared/unit/provider/file' describe Chef::Provider::CookbookFile do let(:node) { double('Chef::Node') } let(:events) { double('Chef::Events').as_null_object } # mock all the methods let(:run_context) { double('Chef::RunContext', :node => node, :events => events) } let(:enclosing_directory) { canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates"))) } let(:resource_path) { canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt"))) } # Subject let(:provider) do provider = described_class.new(resource, run_context) provider.stub!(:content).and_return(content) provider end let(:resource) do resource = Chef::Resource::CookbookFile.new("seattle", @run_context) resource.path(resource_path) resource.cookbook_name = 'apache2' resource end let(:content) do content = mock('Chef::Provider::CookbookFile::Content') end it_behaves_like Chef::Provider::File end chef-11.8.2/spec/unit/provider/remote_file/0000755000004100000410000000000012254362222020575 5ustar www-datawww-datachef-11.8.2/spec/unit/provider/remote_file/fetcher_spec.rb0000644000004100000410000000505512254362222023561 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::RemoteFile::Fetcher do let(:current_resource) { mock("current resource") } let(:new_resource) { mock("new resource") } let(:fetcher_instance) { mock("fetcher") } describe "when passed an http url" do let(:uri) { mock("uri", :scheme => "http" ) } before do Chef::Provider::RemoteFile::HTTP.should_receive(:new).and_return(fetcher_instance) end it "returns an http fetcher" do described_class.for_resource(uri, new_resource, current_resource).should == fetcher_instance end end describe "when passed an https url" do let(:uri) { mock("uri", :scheme => "https" ) } before do Chef::Provider::RemoteFile::HTTP.should_receive(:new).and_return(fetcher_instance) end it "returns an http fetcher" do described_class.for_resource(uri, new_resource, current_resource).should == fetcher_instance end end describe "when passed an ftp url" do let(:uri) { mock("uri", :scheme => "ftp" ) } before do Chef::Provider::RemoteFile::FTP.should_receive(:new).and_return(fetcher_instance) end it "returns an ftp fetcher" do described_class.for_resource(uri, new_resource, current_resource).should == fetcher_instance end end describe "when passed a file url" do let(:uri) { mock("uri", :scheme => "file" ) } before do Chef::Provider::RemoteFile::LocalFile.should_receive(:new).and_return(fetcher_instance) end it "returns a localfile fetcher" do described_class.for_resource(uri, new_resource, current_resource).should == fetcher_instance end end describe "when passed a url we do not recognize" do let(:uri) { mock("uri", :scheme => "xyzzy" ) } it "throws an ArgumentError exception" do lambda { described_class.for_resource(uri, new_resource, current_resource) }.should raise_error(ArgumentError) end end end chef-11.8.2/spec/unit/provider/remote_file/content_spec.rb0000644000004100000410000002015412254362222023610 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::RemoteFile::Content do # # mock setup # let(:current_resource) do Chef::Resource::RemoteFile.new("remote-file-content-spec (current resource)") end let(:source) { [ "http://opscode.com/seattle.txt" ] } let(:new_resource) do r = Chef::Resource::RemoteFile.new("remote-file-content-spec (current resource)") r.source(source) r end let(:run_context) { mock("Chef::RunContext") } # # subject # let(:content) do Chef::Provider::RemoteFile::Content.new(new_resource, current_resource, run_context) end describe "when the checksum of the current_resource matches the checksum set on the resource" do before do new_resource.stub!(:checksum).and_return("0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa") current_resource.stub!(:checksum).and_return("0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa") end it "should return nil for the tempfile" do content.tempfile.should be_nil end it "should not call any fetcher" do Chef::Provider::RemoteFile::Fetcher.should_not_receive(:for_resource) end end describe "when the checksum of the current_resource is a partial match for the checksum set on the resource" do before do new_resource.stub!(:checksum).and_return("0fd012fd") current_resource.stub!(:checksum).and_return("0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa") end it "should return nil for the tempfile" do content.tempfile.should be_nil end it "should not call any fetcher" do Chef::Provider::RemoteFile::Fetcher.should_not_receive(:for_resource) end end shared_examples_for "the resource needs fetching" do before do # FIXME: test one or the other nil, test both not nil and not equal, abuse the regexp a little @uri = mock("URI") URI.should_receive(:parse).with(new_resource.source[0]).and_return(@uri) end describe "when the fetcher returns nil for the tempfile" do before do http_fetcher = mock("Chef::Provider::RemoteFile::HTTP", :fetch => nil) Chef::Provider::RemoteFile::Fetcher.should_receive(:for_resource).with(@uri, new_resource, current_resource).and_return(http_fetcher) end it "should return nil for the tempfile" do content.tempfile.should be_nil end end describe "when the fetcher returns a valid tempfile" do let(:mtime) { Time.now } let(:tempfile) { mock("Tempfile") } let(:http_fetcher) { mock("Chef::Provider::RemoteFile::HTTP", :fetch => tempfile) } before do Chef::Provider::RemoteFile::Fetcher.should_receive(:for_resource).with(@uri, new_resource, current_resource).and_return(http_fetcher) end it "should return the tempfile object to the caller" do content.tempfile.should == tempfile end end end describe "when the checksum are both nil" do before do new_resource.checksum.should be_nil current_resource.checksum.should be_nil end it_behaves_like "the resource needs fetching" end describe "when the current_resource checksum is nil" do before do new_resource.stub!(:checksum).and_return("fd012fd") current_resource.stub!(:checksum).and_return(nil) end it_behaves_like "the resource needs fetching" end describe "when the new_resource checksum is nil" do before do new_resource.stub!(:checksum).and_return(nil) current_resource.stub!(:checksum).and_return("0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa") end it_behaves_like "the resource needs fetching" end describe "when the checksums are a partial match, but not to the leading portion" do before do new_resource.stub!(:checksum).and_return("fd012fd") current_resource.stub!(:checksum).and_return("0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa") end it_behaves_like "the resource needs fetching" end describe "when the fetcher throws an exception" do before do new_resource.stub!(:checksum).and_return(nil) current_resource.stub!(:checksum).and_return(nil) @uri = mock("URI") URI.should_receive(:parse).with(new_resource.source[0]).and_return(@uri) http_fetcher = mock("Chef::Provider::RemoteFile::HTTP") http_fetcher.should_receive(:fetch).and_raise(Errno::ECONNREFUSED) Chef::Provider::RemoteFile::Fetcher.should_receive(:for_resource).with(@uri, new_resource, current_resource).and_return(http_fetcher) end it "should propagate the error back to the caller" do lambda { content.tempfile }.should raise_error(Errno::ECONNREFUSED) end end describe "when there is an array of sources and the first fails" do let(:source) { [ "http://opscode.com/seattle.txt", "http://opscode.com/nyc.txt" ] } before do new_resource.stub!(:checksum).and_return(nil) current_resource.stub!(:checksum).and_return(nil) @uri0 = mock("URI0") @uri1 = mock("URI1") URI.should_receive(:parse).with(new_resource.source[0]).and_return(@uri0) URI.should_receive(:parse).with(new_resource.source[1]).and_return(@uri1) @http_fetcher_throws_exception = mock("Chef::Provider::RemoteFile::HTTP") @http_fetcher_throws_exception.should_receive(:fetch).at_least(:once).and_raise(Errno::ECONNREFUSED) Chef::Provider::RemoteFile::Fetcher.should_receive(:for_resource).with(@uri0, new_resource, current_resource).and_return(@http_fetcher_throws_exception) end describe "when the second url succeeds" do before do @tempfile = mock("Tempfile") mtime = Time.now http_fetcher_works = mock("Chef::Provider::RemoteFile::HTTP", :fetch => @tempfile) Chef::Provider::RemoteFile::Fetcher.should_receive(:for_resource).with(@uri1, new_resource, current_resource).and_return(http_fetcher_works) end it "should return a valid tempfile" do content.tempfile.should == @tempfile end it "should not mutate the new_resource" do content.tempfile new_resource.source.length.should == 2 end end describe "when both urls fail" do before do Chef::Provider::RemoteFile::Fetcher.should_receive(:for_resource).with(@uri1, new_resource, current_resource).and_return(@http_fetcher_throws_exception) end it "should propagate the error back to the caller" do lambda { content.tempfile }.should raise_error(Errno::ECONNREFUSED) end end end describe "when there is an array of sources and the first succeeds" do let(:source) { [ "http://opscode.com/seattle.txt", "http://opscode.com/nyc.txt" ] } before do new_resource.stub!(:checksum).and_return(nil) current_resource.stub!(:checksum).and_return(nil) @uri0 = mock("URI0") URI.should_receive(:parse).with(new_resource.source[0]).and_return(@uri0) URI.should_not_receive(:parse).with(new_resource.source[1]) @tempfile = mock("Tempfile") mtime = Time.now http_fetcher_works = mock("Chef::Provider::RemoteFile::HTTP", :fetch => @tempfile) Chef::Provider::RemoteFile::Fetcher.should_receive(:for_resource).with(@uri0, new_resource, current_resource).and_return(http_fetcher_works) end it "should return a valid tempfile" do content.tempfile.should == @tempfile end it "should not mutate the new_resource" do content.tempfile new_resource.source.length.should == 2 end end end chef-11.8.2/spec/unit/provider/remote_file/cache_control_data_spec.rb0000644000004100000410000001676212254362222025744 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'uri' CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH = 64 CACHE_FILE_MD5_HEX_LENGTH = 32 CACHE_FILE_JSON_FILE_EXTENSION_LENGTH = 5 CACHE_FILE_PATH_LIMIT = CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH + 1 + CACHE_FILE_MD5_HEX_LENGTH + CACHE_FILE_JSON_FILE_EXTENSION_LENGTH # {friendly}-{md5hex}.json == 102 describe Chef::Provider::RemoteFile::CacheControlData do let(:uri) { URI.parse("http://www.google.com/robots.txt") } subject(:cache_control_data) do Chef::Provider::RemoteFile::CacheControlData.load_and_validate(uri, current_file_checksum) end let(:cache_path) { "remote_file/http___www_google_com_robots_txt-9839677abeeadf0691026e0cabca2339.json" } # the checksum of the file we have on disk already let(:current_file_checksum) { "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" } context "when loading data for an unknown URI" do before do Chef::FileCache.should_receive(:load).with(cache_path).and_raise(Chef::Exceptions::FileNotFound, "nope") end context "and there is no current copy of the file" do let(:current_file_checksum) { nil } it "returns empty cache control data" do cache_control_data.etag.should be_nil cache_control_data.mtime.should be_nil end end it "returns empty cache control data" do cache_control_data.etag.should be_nil cache_control_data.mtime.should be_nil end context "and the URI contains a password" do let(:uri) { URI.parse("http://bob:password@example.org/") } let(:cache_path) { "remote_file/http___bob_XXXX_example_org_-f121caacb74c05a35bcefdf578ed5fc9.json" } it "loads the cache data from a path based on a sanitized URI" do Chef::Provider::RemoteFile::CacheControlData.load_and_validate(uri, current_file_checksum) end end end describe "when loading data for a known URI" do # the checksum of the file last we fetched it. let(:last_fetched_checksum) { "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" } let(:etag) { "\"a-strong-identifier\"" } let(:mtime) { "Tue, 21 May 2013 19:19:23 GMT" } let(:cache_json_data) do cache = {} cache["etag"] = etag cache["mtime"] = mtime cache["checksum"] = last_fetched_checksum cache.to_json end before do Chef::FileCache.should_receive(:load).with(cache_path).and_return(cache_json_data) end context "and there is no on-disk copy of the file" do let(:current_file_checksum) { nil } it "returns empty cache control data" do cache_control_data.etag.should be_nil cache_control_data.mtime.should be_nil end end context "and the cached checksum does not match the on-disk copy" do let(:current_file_checksum) { "e2a8938cc31754f6c067b35aab1d0d4864272e9bf8504536ef3e79ebf8432305" } it "returns empty cache control data" do cache_control_data.etag.should be_nil cache_control_data.mtime.should be_nil end end context "and the cached checksum matches the on-disk copy" do it "populates the cache control data" do cache_control_data.etag.should == etag cache_control_data.mtime.should == mtime end end context "and the cached checksum data is corrupted" do let(:cache_json_data) { '{"foo",,"bar" []}' } it "returns empty cache control data" do cache_control_data.etag.should be_nil cache_control_data.mtime.should be_nil end end end describe "when saving to disk" do let(:etag) { "\"a-strong-identifier\"" } let(:mtime) { "Tue, 21 May 2013 19:19:23 GMT" } let(:fetched_file_checksum) { "e2a8938cc31754f6c067b35aab1d0d4864272e9bf8504536ef3e79ebf8432305" } let(:expected_serialization_data) do data = {} data["etag"] = etag data["mtime"] = mtime data["checksum"] = fetched_file_checksum data end before do cache_control_data.etag = etag cache_control_data.mtime = mtime cache_control_data.checksum = fetched_file_checksum end it "serializes its attributes to JSON" do # we have to test this separately because ruby 1.8 hash order is unstable # so we can't count on the order of the keys in the json format. json_data = cache_control_data.json_data Chef::JSONCompat.from_json(json_data).should == expected_serialization_data end it "writes data to the cache" do json_data = cache_control_data.json_data Chef::FileCache.should_receive(:store).with(cache_path, json_data) cache_control_data.save end context "and the URI contains a password" do let(:uri) { URI.parse("http://bob:password@example.org/") } let(:cache_path) { "remote_file/http___bob_XXXX_example_org_-f121caacb74c05a35bcefdf578ed5fc9.json" } it "writes the data to the cache with a sanitized path name" do json_data = cache_control_data.json_data Chef::FileCache.should_receive(:store).with(cache_path, json_data) cache_control_data.save end end # Cover the very long remote file path case -- see CHEF-4422 where # local cache file names generated from the long uri exceeded # local file system path limits resulting in exceptions from # file system API's on both Windows and Unix systems. context "and the URI results in a file cache path that exceeds #{CACHE_FILE_PATH_LIMIT} characters in length" do let(:long_remote_path) { "http://www.bing.com/" + ('0' * (CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH * 2 )) } let(:uri) { URI.parse(long_remote_path) } let(:truncated_remote_uri) { URI.parse(long_remote_path[0...CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH]) } let(:truncated_file_cache_path) do cache_control_data_truncated = Chef::Provider::RemoteFile::CacheControlData.load_and_validate(truncated_remote_uri, current_file_checksum) cache_control_data_truncated.send('sanitized_cache_file_basename')[0...CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH] end it "truncates the file cache path to 102 characters" do normalized_cache_path = cache_control_data.send('sanitized_cache_file_basename') Chef::FileCache.should_receive(:store).with("remote_file/" + normalized_cache_path, cache_control_data.json_data) cache_control_data.save normalized_cache_path.length.should == CACHE_FILE_PATH_LIMIT end it "uses a file cache path that starts with the first #{CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH} characters of the URI" do normalized_cache_path = cache_control_data.send('sanitized_cache_file_basename') truncated_file_cache_path.length.should == CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH normalized_cache_path.start_with?(truncated_file_cache_path).should == true end end end end chef-11.8.2/spec/unit/provider/remote_file/local_file_spec.rb0000644000004100000410000000372712254362222024236 0ustar www-datawww-data# # Author:: Jesse Campbell () # Copyright:: Copyright (c) 2013 Jesse Campbell # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::RemoteFile::LocalFile do let(:uri) { URI.parse("file:///nyan_cat.png") } let(:new_resource) { Chef::Resource::RemoteFile.new("local file backend test (new_resource)") } let(:current_resource) { Chef::Resource::RemoteFile.new("local file backend test (current_resource)") } subject(:fetcher) { Chef::Provider::RemoteFile::LocalFile.new(uri, new_resource, current_resource) } context "when first created" do it "stores the uri it is passed" do fetcher.uri.should == uri end it "stores the new_resource" do fetcher.new_resource.should == new_resource end end describe "when fetching the object" do let(:tempfile) { mock("Tempfile", :path => "/tmp/foo/bar/nyan.png", :close => nil) } let(:chef_tempfile) { mock("Chef::FileContentManagement::Tempfile", :tempfile => tempfile) } before do current_resource.source("file:///nyan_cat.png") end it "stages the local file to a temporary file" do Chef::FileContentManagement::Tempfile.should_receive(:new).with(new_resource).and_return(chef_tempfile) ::FileUtils.should_receive(:cp).with(uri.path, tempfile.path) tempfile.should_receive(:close) result = fetcher.fetch result.should == tempfile end end end chef-11.8.2/spec/unit/provider/remote_file/http_spec.rb0000644000004100000410000002476212254362222023126 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Lamont Granquist # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::RemoteFile::HTTP do let(:uri) { URI.parse("http://opscode.com/seattle.txt") } let(:existing_file_source) { nil } let(:current_resource_checksum) { "41e78735319af11327e9d2ca8535ea1c191e5ac1f76bb08d88fe6c3f93a8c8e5" } let(:current_resource) do current_resource = Chef::Resource::RemoteFile.new("/tmp/foo.txt") current_resource.source(existing_file_source) if existing_file_source current_resource.checksum(current_resource_checksum) current_resource end let(:new_resource) do Chef::Resource::RemoteFile.new("/tmp/foo.txt") end subject(:fetcher) do Chef::Provider::RemoteFile::HTTP.new(uri, new_resource, current_resource) end let(:cache_control_data) { Chef::Provider::RemoteFile::CacheControlData.new(uri) } describe "generating cache control headers" do context "and there is no valid cache control data for this URI on disk" do before do Chef::Provider::RemoteFile::CacheControlData.should_receive(:load_and_validate).with(uri, current_resource_checksum).and_return(cache_control_data) end it "does not add conditional GET headers" do fetcher.conditional_get_headers.should == {} end context "and the resource specifies custom headers" do before do new_resource.headers("x-myapp-header" => "custom-header-value") end it "has the user-specified custom headers" do fetcher.headers.should == {"x-myapp-header" => "custom-header-value"} end end end context "and the cache control data matches the existing file" do # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26 let(:etag) { "\"a-strong-unique-identifier\"" } # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 let(:mtime) { "Tue, 21 May 2013 19:19:23 GMT" } before do cache_control_data.etag = etag cache_control_data.mtime = mtime Chef::Provider::RemoteFile::CacheControlData.should_receive(:load_and_validate).with(uri, current_resource_checksum).and_return(cache_control_data) end context "and no conditional get features are enabled" do before do new_resource.use_conditional_get(false) end it "does not add headers to the request" do fetcher.headers.should == {} end end context "and conditional get is enabled" do before do new_resource.use_conditional_get(true) end it "adds If-None-Match and If-Modified-Since headers to the request" do headers = fetcher.headers headers["if-none-match"].should == etag headers["if-modified-since"].should == mtime end context "and custom headers are provided" do before do new_resource.headers("x-myapp-header" => "app-specific-header", "if-none-match" => "custom-etag", "if-modified-since" => "custom-last-modified") end it "preserves non-conflicting headers" do fetcher.headers["x-myapp-header"].should == "app-specific-header" end it "prefers user-supplied cache control headers" do headers = fetcher.headers headers["if-none-match"].should == "custom-etag" headers["if-modified-since"].should == "custom-last-modified" end end end context "and etag support is enabled" do before do new_resource.use_conditional_get(false) new_resource.use_etags(true) end it "only adds If-None-Match headers to the request" do headers = fetcher.headers headers["if-none-match"].should == etag headers.should_not have_key("if-modified-since") end end context "and mtime support is enabled" do before do new_resource.use_conditional_get(false) new_resource.use_last_modified(true) end it "only adds If-Modified-Since headers to the request" do headers = fetcher.headers headers["if-modified-since"].should == mtime headers.should_not have_key("if-none-match") end end end end describe "when fetching the uri" do let(:expected_http_opts) { {} } let(:expected_http_args) { [uri, expected_http_opts] } let(:tempfile_path) { "/tmp/chef-mock-tempfile-abc123" } let(:tempfile) { mock(Tempfile, :path => tempfile_path, :close => nil) } let(:last_response) { {} } let(:rest) do rest = mock(Chef::HTTP::Simple) rest.stub!(:streaming_request).and_return(tempfile) rest.stub!(:last_response).and_return(last_response) rest end before do new_resource.headers({}) new_resource.use_last_modified(false) Chef::Provider::RemoteFile::CacheControlData.should_receive(:load_and_validate).with(uri, current_resource_checksum).and_return(cache_control_data) Chef::HTTP::Simple.should_receive(:new).with(*expected_http_args).and_return(rest) end describe "and the request does not return new content" do it "should return a nil tempfile for a 304 HTTPNotModifed" do # Streaming request returns nil for 304 errors rest.stub(:streaming_request).and_return(nil) fetcher.fetch.should be_nil end end describe "and the request returns new content" do let(:fetched_content_checksum) { "e2a8938cc31754f6c067b35aab1d0d4864272e9bf8504536ef3e79ebf8432305" } before do cache_control_data.should_receive(:save) Chef::Digester.should_receive(:checksum_for_file).with(tempfile_path).and_return(fetched_content_checksum) end it "should return a tempfile" do result = fetcher.fetch result.should == tempfile cache_control_data.etag.should be_nil cache_control_data.mtime.should be_nil cache_control_data.checksum.should == fetched_content_checksum end context "and the response does not contain an etag" do let(:last_response) { {"etag" => nil} } it "does not include an etag in the result" do fetcher.fetch cache_control_data.etag.should be_nil cache_control_data.mtime.should be_nil cache_control_data.checksum.should == fetched_content_checksum end end context "and the response has an etag header" do let(:last_response) { {"etag" => "abc123"} } it "includes the etag value in the response" do fetcher.fetch cache_control_data.etag.should == "abc123" cache_control_data.mtime.should be_nil cache_control_data.checksum.should == fetched_content_checksum end end context "and the response has no Date or Last-Modified header" do let(:last_response) { {"date" => nil, "last_modified" => nil} } it "does not set an mtime in the result" do # RFC 2616 suggests that servers that do not set a Date header do not # have a reliable clock, so no use in making them deal with dates. fetcher.fetch cache_control_data.etag.should be_nil cache_control_data.mtime.should be_nil cache_control_data.checksum.should == fetched_content_checksum end end context "and the response has a Last-Modified header" do let(:last_response) do # Last-Modified should be preferred to Date if both are set {"date" => "Fri, 17 May 2013 23:23:23 GMT", "last_modified" => "Fri, 17 May 2013 11:11:11 GMT"} end it "sets the mtime to the Last-Modified time in the response" do fetcher.fetch cache_control_data.etag.should be_nil cache_control_data.mtime.should == last_response["last_modified"] end end context "and the response has a Date header but no Last-Modified header" do let(:last_response) do {"date" => "Fri, 17 May 2013 23:23:23 GMT", "last_modified" => nil} end it "sets the mtime to the Date in the response" do fetcher.fetch cache_control_data.etag.should be_nil cache_control_data.mtime.should == last_response["date"] cache_control_data.checksum.should == fetched_content_checksum end end context "and the target file is a tarball [CHEF-3140]" do let(:uri) { URI.parse("http://opscode.com/tarball.tgz") } let(:expected_http_opts) { {:disable_gzip => true} } # CHEF-3140 # Some servers return tarballs as content type tar and encoding gzip, which # is totally wrong. When this happens and gzip isn't disabled, Chef::HTTP::Simple # will decompress the file for you, which is not at all what you expected # to happen (you end up with an uncomressed tar archive instead of the # gzipped tar archive you expected). To work around this behavior, we # detect when users are fetching gzipped files and turn off gzip in # Chef::HTTP::Simple. it "should disable gzip compression in the client" do # Before block in the parent context has set an expectation on # Chef::HTTP::Simple.new() being called with expected arguments. Here we fufil # that expectation, so that we can explicitly set it for this test. # This is intended to provide insurance that refactoring of the parent # context does not negate the value of this particular example. Chef::HTTP::Simple.new(*expected_http_args) Chef::HTTP::Simple.should_receive(:new).once.with(*expected_http_args).and_return(rest) fetcher.fetch cache_control_data.etag.should be_nil cache_control_data.mtime.should be_nil cache_control_data.checksum.should == fetched_content_checksum end end end end end chef-11.8.2/spec/unit/provider/remote_file/ftp_spec.rb0000644000004100000410000001620712254362222022733 0ustar www-datawww-data# # Author:: Jesse Campbell () # Copyright:: Copyright (c) 2013 Jesse Campbell # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::RemoteFile::FTP do let(:enclosing_directory) { canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates"))) } let(:resource_path) { canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt"))) } let(:new_resource) do r = Chef::Resource::RemoteFile.new("remote file ftp backend test (new resource)") r.ftp_active_mode(false) r.path(resource_path) r end let(:current_resource) do Chef::Resource::RemoteFile.new("remote file ftp backend test (current resource)'") end let(:ftp) do ftp = mock(Net::FTP, { }) ftp.stub!(:connect) ftp.stub!(:login) ftp.stub!(:voidcmd) ftp.stub!(:mtime).and_return(Time.now) ftp.stub!(:getbinaryfile) ftp.stub!(:close) ftp.stub!(:passive=) ftp end let(:tempfile_path) { "/tmp/somedir/remote-file-ftp-backend-spec-test" } let(:tempfile) do t = StringIO.new t.stub(:path).and_return(tempfile_path) t end let(:uri) { URI.parse("ftp://opscode.com/seattle.txt") } before(:each) do Net::FTP.stub!(:new).with().and_return(ftp) Tempfile.stub!(:new).and_return(tempfile) end describe "when first created" do it "throws an argument exception when no path is given" do uri.path = "" lambda { Chef::Provider::RemoteFile::FTP.new(uri, new_resource, current_resource) }.should raise_error(ArgumentError) end it "throws an argument exception when only a / is given" do uri.path = "/" lambda { Chef::Provider::RemoteFile::FTP.new(uri, new_resource, current_resource) }.should raise_error(ArgumentError) end it "throws an argument exception when no filename is given" do uri.path = "/the/whole/path/" lambda { Chef::Provider::RemoteFile::FTP.new(uri, new_resource, current_resource) }.should raise_error(ArgumentError) end it "throws an argument exception when the typecode is invalid" do uri.typecode = "d" lambda { Chef::Provider::RemoteFile::FTP.new(uri, new_resource, current_resource) }.should raise_error(ArgumentError) end it "does not use passive mode when new_resource sets ftp_active_mode to true" do new_resource.ftp_active_mode(true) fetcher = Chef::Provider::RemoteFile::FTP.new(uri, new_resource, current_resource) fetcher.use_passive_mode?.should be_false end it "uses passive mode when new_resource sets ftp_active_mode to false" do new_resource.ftp_active_mode(false) fetcher = Chef::Provider::RemoteFile::FTP.new(uri, new_resource, current_resource) fetcher.use_passive_mode?.should be_true end end describe "when fetching the object" do let(:cache_control_data) { Chef::Provider::RemoteFile::CacheControlData.new(uri) } let(:current_resource_checksum) { "e2a8938cc31754f6c067b35aab1d0d4864272e9bf8504536ef3e79ebf8432305" } subject(:fetcher) { Chef::Provider::RemoteFile::FTP.new(uri, new_resource, current_resource) } before do current_resource.checksum(current_resource_checksum) #Chef::Provider::RemoteFile::CacheControlData.should_receive(:load_and_validate).with(uri, current_resource_checksum).and_return(cache_control_data) end it "should connect to the host from the uri on the default port 21" do ftp.should_receive(:connect).with("opscode.com", 21) fetcher.fetch end it "should set passive true when ftp_active_mode is false" do new_resource.ftp_active_mode(false) ftp.should_receive(:passive=).with(true) fetcher.fetch end it "should set passive false when ftp_active_mode is false" do new_resource.ftp_active_mode(true) ftp.should_receive(:passive=).with(false) fetcher.fetch end it "should use anonymous ftp when no userinfo is provided" do ftp.should_receive(:login).with("anonymous", nil) fetcher.fetch end context "and the URI specifies an alternate port" do let(:uri) { URI.parse("ftp://opscode.com:8021/seattle.txt") } it "should connect on an alternate port when one is provided" do uri = URI.parse("ftp://opscode.com:8021/seattle.txt") ftp.should_receive(:connect).with("opscode.com", 8021) fetcher.fetch end end context "and the URI contains a username and password" do let(:uri) { URI.parse("ftp://the_user:the_password@opscode.com/seattle.txt") } it "should use authenticated ftp when userinfo is provided" do ftp.should_receive(:login).with("the_user", "the_password") fetcher.fetch end end context "and the uri sets the typecode to ascii" do let(:uri) { URI.parse("ftp://the_user:the_password@opscode.com/seattle.txt;type=a") } it "fetches the file with ascii typecode set" do ftp.should_receive(:voidcmd).with("TYPE A").once fetcher.fetch end end context "and the uri sets the typecode to image" do let(:uri) { URI.parse("ftp://the_user:the_password@opscode.com/seattle.txt;type=i") } it "should accept image for the typecode" do ftp.should_receive(:voidcmd).with("TYPE I").once fetcher.fetch end end context "and the uri specifies a nested path" do let(:uri) { URI.parse("ftp://opscode.com/the/whole/path/seattle.txt") } it "should fetch the file from the correct path" do ftp.should_receive(:voidcmd).with("CWD the").once ftp.should_receive(:voidcmd).with("CWD whole").once ftp.should_receive(:voidcmd).with("CWD path").once ftp.should_receive(:getbinaryfile).with("seattle.txt", tempfile.path) fetcher.fetch end end context "when not using last modified based conditional fetching" do before do new_resource.use_last_modified(false) end it "should return a tempfile in the result" do result = fetcher.fetch result.should equal(tempfile) end end context "and proxying is enabled" do before do Chef::Config[:ftp_proxy] = "socks5://socks.example.com:5000" Chef::Config[:ftp_proxy_user] = "bill" Chef::Config[:ftp_proxy_pass] = "ted" end it "fetches the file via the proxy" do current_socks_server = ENV["SOCKS_SERVER"] ENV.should_receive(:[]=).with("SOCKS_SERVER", "socks5://bill:ted@socks.example.com:5000").ordered ENV.should_receive(:[]=).with("SOCKS_SERVER", current_socks_server).ordered result = fetcher.fetch result.should equal(tempfile) end end end end chef-11.8.2/spec/unit/provider/user_spec.rb0000644000004100000410000003725212254362222020631 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' EtcPwnamIsh = Struct.new(:name, :passwd, :uid, :gid, :gecos, :dir, :shell, :change, :uclass, :expire) EtcGrnamIsh = Struct.new(:name, :passwd, :gid, :mem) describe Chef::Provider::User do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::User.new("adam") @new_resource.comment "Adam Jacob" @new_resource.uid 1000 @new_resource.gid 1000 @new_resource.home "/home/adam" @new_resource.shell "/usr/bin/zsh" @current_resource = Chef::Resource::User.new("adam") @current_resource.comment "Adam Jacob" @current_resource.uid 1000 @current_resource.gid 1000 @current_resource.home "/home/adam" @current_resource.shell "/usr/bin/zsh" @provider = Chef::Provider::User.new(@new_resource, @run_context) @provider.current_resource = @current_resource end describe "when first created" do it "assume the user exists by default" do @provider.user_exists.should eql(true) end it "does not know the locked state" do @provider.locked.should eql(nil) end end describe "executing load_current_resource" do before(:each) do @node = Chef::Node.new #@new_resource = mock("Chef::Resource::User", # :null_object => true, # :username => "adam", # :comment => "Adam Jacob", # :uid => 1000, # :gid => 1000, # :home => "/home/adam", # :shell => "/usr/bin/zsh", # :password => nil, # :updated => nil #) Chef::Resource::User.stub!(:new).and_return(@current_resource) @pw_user = EtcPwnamIsh.new @pw_user.name = "adam" @pw_user.gid = 1000 @pw_user.uid = 1000 @pw_user.gecos = "Adam Jacob" @pw_user.dir = "/home/adam" @pw_user.shell = "/usr/bin/zsh" @pw_user.passwd = "*" Etc.stub!(:getpwnam).and_return(@pw_user) end it "should create a current resource with the same name as the new resource" do @provider.load_current_resource @provider.current_resource.name.should == 'adam' end it "should set the username of the current resource to the username of the new resource" do @provider.load_current_resource @current_resource.username.should == @new_resource.username end it "should look up the user in /etc/passwd with getpwnam" do Etc.should_receive(:getpwnam).with(@new_resource.username).and_return(@pw_user) @provider.load_current_resource end it "should set user_exists to false if the user is not found with getpwnam" do Etc.should_receive(:getpwnam).and_raise(ArgumentError) @provider.load_current_resource @provider.user_exists.should eql(false) end # The mapping between the Chef::Resource::User and Getpwnam struct user_attrib_map = { :uid => :uid, :gid => :gid, :comment => :gecos, :home => :dir, :shell => :shell } user_attrib_map.each do |user_attrib, getpwnam_attrib| it "should set the current resources #{user_attrib} based on getpwnam #{getpwnam_attrib}" do @current_resource.should_receive(user_attrib).with(@pw_user.send(getpwnam_attrib)) @provider.load_current_resource end end it "should attempt to convert the group gid if one has been supplied" do @provider.should_receive(:convert_group_name) @provider.load_current_resource end it "shouldn't try and convert the group gid if none has been supplied" do @new_resource.stub!(:gid).and_return(nil) @provider.should_not_receive(:convert_group_name) @provider.load_current_resource end it "should return the current resource" do @provider.load_current_resource.should eql(@current_resource) end describe "and running assertions" do def self.shadow_lib_unavail? begin require 'rubygems' require 'shadow' rescue LoadError => e pending "ruby-shadow gem not installed for dynamic load test" true else false end end before (:each) do user = @pw_user.dup user.name = "root" user.passwd = "x" @new_resource.password "some new password" Etc.stub!(:getpwnam).and_return(user) end unless shadow_lib_unavail? context "and we have the ruby-shadow gem" do pending "and we are not root (rerun this again as root)", :requires_unprivileged_user => true context "and we are root", :requires_root => true do it "should pass assertions when ruby-shadow can be loaded" do @provider.action = 'create' original_method = @provider.method(:require) @provider.should_receive(:require) { |*args| original_method.call(*args) } passwd_info = Struct::PasswdEntry.new(:sp_namp => "adm ", :sp_pwdp => "$1$T0N0Q.lc$nyG6pFI3Dpqa5cxUz/57j0", :sp_lstchg => 14861, :sp_min => 0, :sp_max => 99999, :sp_warn => 7, :sp_inact => -1, :sp_expire => -1, :sp_flag => -1) Shadow::Passwd.should_receive(:getspnam).with("adam").and_return(passwd_info) @provider.load_current_resource @provider.define_resource_requirements @provider.process_resource_requirements end end end end it "should fail assertions when ruby-shadow cannot be loaded" do @provider.should_receive(:require).with("shadow") { raise LoadError } @provider.load_current_resource @provider.define_resource_requirements lambda {@provider.process_resource_requirements}.should raise_error Chef::Exceptions::MissingLibrary end end end describe "compare_user" do let(:mapping) { { 'username' => ["adam", "Adam"], 'comment' => ["Adam Jacob", "adam jacob"], 'uid' => [1000, 1001], 'gid' => [1000, 1001], 'home' => ["/home/adam", "/Users/adam"], 'shell'=> ["/usr/bin/zsh", "/bin/bash"], 'password'=> ["abcd","12345"] } } %w{uid gid comment home shell password}.each do |attribute| it "should return true if #{attribute} doesn't match" do @new_resource.send(attribute, mapping[attribute][0]) @current_resource.send(attribute, mapping[attribute][1]) @provider.compare_user.should eql(true) end end %w{uid gid}.each do |attribute| it "should return false if string #{attribute} matches fixnum" do @new_resource.send(attribute, "100") @current_resource.send(attribute, 100) @provider.compare_user.should eql(false) end end it "should return false if the objects are identical" do @provider.compare_user.should eql(false) end end describe "action_create" do before(:each) do @provider.stub!(:load_current_resource) # @current_resource = mock("Chef::Resource::User", # :null_object => true, # :username => "adam", # :comment => "Adam Jacob", # :uid => 1000, # :gid => 1000, # :home => "/home/adam", # :shell => "/usr/bin/zsh", # :password => nil, # :updated => nil # ) # @provider = Chef::Provider::User.new(@node, @new_resource) # @provider.current_resource = @current_resource # @provider.user_exists = false # @provider.stub!(:create_user).and_return(true) # @provider.stub!(:manage_user).and_return(true) end it "should call create_user if the user does not exist" do @provider.user_exists = false @provider.should_receive(:create_user).and_return(true) @provider.action_create @provider.set_updated_status @new_resource.should be_updated end it "should call manage_user if the user exists and has mismatched attributes" do @provider.user_exists = true @provider.stub!(:compare_user).and_return(true) @provider.should_receive(:manage_user).and_return(true) @provider.action_create end it "should set the new_resources updated flag when it creates the user if we call manage_user" do @provider.user_exists = true @provider.stub!(:compare_user).and_return(true) @provider.stub!(:manage_user).and_return(true) @provider.action_create @provider.set_updated_status @new_resource.should be_updated end end describe "action_remove" do before(:each) do @provider.stub!(:load_current_resource) end it "should not call remove_user if the user does not exist" do @provider.user_exists = false @provider.should_not_receive(:remove_user) @provider.action_remove end it "should call remove_user if the user exists" do @provider.user_exists = true @provider.should_receive(:remove_user) @provider.action_remove end it "should set the new_resources updated flag to true if the user is removed" do @provider.user_exists = true @provider.should_receive(:remove_user) @provider.action_remove @provider.set_updated_status @new_resource.should be_updated end end describe "action_manage" do before(:each) do @provider.stub!(:load_current_resource) # @node = Chef::Node.new # @new_resource = mock("Chef::Resource::User", # :null_object => true # ) # @current_resource = mock("Chef::Resource::User", # :null_object => true # ) # @provider = Chef::Provider::User.new(@node, @new_resource) # @provider.current_resource = @current_resource # @provider.user_exists = true # @provider.stub!(:manage_user).and_return(true) end it "should run manage_user if the user exists and has mismatched attributes" do @provider.should_receive(:compare_user).and_return(true) @provider.should_receive(:manage_user).and_return(true) @provider.action_manage end it "should set the new resources updated flag to true if manage_user is called" do @provider.stub!(:compare_user).and_return(true) @provider.stub!(:manage_user).and_return(true) @provider.action_manage @provider.set_updated_status @new_resource.should be_updated end it "should not run manage_user if the user does not exist" do @provider.user_exists = false @provider.should_not_receive(:manage_user) @provider.action_manage end it "should not run manage_user if the user exists but has no differing attributes" do @provider.should_receive(:compare_user).and_return(false) @provider.should_not_receive(:manage_user) @provider.action_manage end end describe "action_modify" do before(:each) do @provider.stub!(:load_current_resource) # @node = Chef::Node.new # @new_resource = mock("Chef::Resource::User", # :null_object => true # ) # @current_resource = mock("Chef::Resource::User", # :null_object => true # ) # @provider = Chef::Provider::User.new(@node, @new_resource) # @provider.current_resource = @current_resource # @provider.user_exists = true # @provider.stub!(:manage_user).and_return(true) end it "should run manage_user if the user exists and has mismatched attributes" do @provider.should_receive(:compare_user).and_return(true) @provider.should_receive(:manage_user).and_return(true) @provider.action_modify end it "should set the new resources updated flag to true if manage_user is called" do @provider.stub!(:compare_user).and_return(true) @provider.stub!(:manage_user).and_return(true) @provider.action_modify @provider.set_updated_status @new_resource.should be_updated end it "should not run manage_user if the user exists but has no differing attributes" do @provider.should_receive(:compare_user).and_return(false) @provider.should_not_receive(:manage_user) @provider.action_modify end it "should raise a Chef::Exceptions::User if the user doesn't exist" do @provider.user_exists = false lambda { @provider.action = :modify; @provider.run_action }.should raise_error(Chef::Exceptions::User) end end describe "action_lock" do before(:each) do @provider.stub!(:load_current_resource) end it "should lock the user if it exists and is unlocked" do @provider.stub!(:check_lock).and_return(false) @provider.should_receive(:lock_user).and_return(true) @provider.action_lock end it "should set the new resources updated flag to true if lock_user is called" do @provider.stub!(:check_lock).and_return(false) @provider.should_receive(:lock_user) @provider.action_lock @provider.set_updated_status @new_resource.should be_updated end it "should raise a Chef::Exceptions::User if we try and lock a user that does not exist" do @provider.user_exists = false @provider.action = :lock lambda { @provider.run_action }.should raise_error(Chef::Exceptions::User) end end describe "action_unlock" do before(:each) do @provider.stub!(:load_current_resource) # @node = Chef::Node.new # @new_resource = mock("Chef::Resource::User", # :null_object => true # ) # @current_resource = mock("Chef::Resource::User", # :null_object => true # ) # @provider = Chef::Provider::User.new(@node, @new_resource) # @provider.current_resource = @current_resource # @provider.user_exists = true # @provider.stub!(:check_lock).and_return(true) # @provider.stub!(:unlock_user).and_return(true) end it "should unlock the user if it exists and is locked" do @provider.stub!(:check_lock).and_return(true) @provider.should_receive(:unlock_user).and_return(true) @provider.action_unlock @provider.set_updated_status @new_resource.should be_updated end it "should raise a Chef::Exceptions::User if we try and unlock a user that does not exist" do @provider.user_exists = false @provider.action = :unlock lambda { @provider.run_action }.should raise_error(Chef::Exceptions::User) end end describe "convert_group_name" do before do @new_resource.gid('999') @group = EtcGrnamIsh.new('wheel', '*', 999, []) end it "should lookup the group name locally" do Etc.should_receive(:getgrnam).with("999").and_return(@group) @provider.convert_group_name.should == 999 end it "should raise an error if we can't translate the group name during resource assertions" do Etc.should_receive(:getgrnam).and_raise(ArgumentError) @provider.define_resource_requirements @provider.convert_group_name lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::User) end it "should set the new resources gid to the integerized version if available" do Etc.should_receive(:getgrnam).with("999").and_return(@group) @provider.convert_group_name @new_resource.gid.should == 999 end end end chef-11.8.2/spec/unit/provider/directory_spec.rb0000644000004100000410000001622512254362222021654 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'ostruct' require 'spec_helper' require 'tmpdir' describe Chef::Provider::Directory do before(:each) do @new_resource = Chef::Resource::Directory.new(Dir.tmpdir) if !windows? @new_resource.owner(500) @new_resource.group(500) @new_resource.mode(0644) end @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @directory = Chef::Provider::Directory.new(@new_resource, @run_context) end describe "scanning file security metadata on windows" do before do end it "describes the directory's access rights" do pending end end describe "scanning file security metadata on unix" do before do Chef::Platform.stub!(:windows?).and_return(false) end let(:mock_stat) do cstats = mock("stats") cstats.stub!(:uid).and_return(500) cstats.stub!(:gid).and_return(500) cstats.stub!(:mode).and_return(0755) cstats end it "describes the access mode as a String of octal integers" do File.stub!(:exists?).and_return(true) File.should_receive(:stat).and_return(mock_stat) @directory.load_current_resource @directory.current_resource.mode.should == "0755" end context "when user and group are specified with UID/GID" do it "describes the current owner and group as UID and GID" do File.stub!(:exists?).and_return(true) File.should_receive(:stat).and_return(mock_stat) @directory.load_current_resource @directory.current_resource.path.should eql(@new_resource.path) @directory.current_resource.owner.should eql(500) @directory.current_resource.group.should eql(500) end end context "when user/group are specified with user/group names" do end end # Unix only for now. While file security attribute reporting for windows is # disabled, unix and windows differ in the number of exists? calls that are # made by the provider. it "should create a new directory on create, setting updated to true", :unix_only do @new_resource.path "/tmp/foo" File.should_receive(:exists?).at_least(:once).and_return(false) File.should_receive(:directory?).with("/tmp").and_return(true) Dir.should_receive(:mkdir).with(@new_resource.path).once.and_return(true) @directory.should_receive(:do_acl_changes) @directory.stub!(:do_selinux) @directory.run_action(:create) @directory.new_resource.should be_updated end it "should raise an exception if the parent directory does not exist and recursive is false" do @new_resource.path "/tmp/some/dir" @new_resource.recursive false lambda { @directory.run_action(:create) }.should raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist) end # Unix only for now. While file security attribute reporting for windows is # disabled, unix and windows differ in the number of exists? calls that are # made by the provider. it "should create a new directory when parent directory does not exist if recursive is true and permissions are correct", :unix_only do @new_resource.path "/path/to/dir" @new_resource.recursive true File.should_receive(:exists?).with(@new_resource.path).ordered.and_return(false) File.should_receive(:exists?).with('/path/to').ordered.and_return(false) File.should_receive(:exists?).with('/path').ordered.and_return(true) File.should_receive(:writable?).with('/path').ordered.and_return(true) File.should_receive(:exists?).with(@new_resource.path).ordered.and_return(false) FileUtils.should_receive(:mkdir_p).with(@new_resource.path).and_return(true) @directory.should_receive(:do_acl_changes) @directory.stub!(:do_selinux) @directory.run_action(:create) @new_resource.should be_updated end it "should raise an error when creating a directory when parent directory is a file" do File.should_receive(:directory?).and_return(false) Dir.should_not_receive(:mkdir).with(@new_resource.path) lambda { @directory.run_action(:create) }.should raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist) @directory.new_resource.should_not be_updated end # Unix only for now. While file security attribute reporting for windows is # disabled, unix and windows differ in the number of exists? calls that are # made by the provider. it "should not create the directory if it already exists", :unix_only do stub_file_cstats @new_resource.path "/tmp/foo" File.should_receive(:directory?).at_least(:once).and_return(true) File.should_receive(:writable?).with("/tmp").and_return(true) File.should_receive(:exists?).at_least(:once).and_return(true) Dir.should_not_receive(:mkdir).with(@new_resource.path) @directory.should_receive(:do_acl_changes) @directory.run_action(:create) end it "should delete the directory if it exists, and is writable with action_delete" do File.should_receive(:directory?).and_return(true) File.should_receive(:writable?).once.and_return(true) Dir.should_receive(:delete).with(@new_resource.path).once.and_return(true) @directory.run_action(:delete) end it "should raise an exception if it cannot delete the directory due to bad permissions" do File.stub!(:exists?).and_return(true) File.stub!(:writable?).and_return(false) lambda { @directory.run_action(:delete) }.should raise_error(RuntimeError) end it "should take no action when deleting a target directory that does not exist" do @new_resource.path "/an/invalid/path" File.stub!(:exists?).and_return(false) Dir.should_not_receive(:delete).with(@new_resource.path) @directory.run_action(:delete) @directory.new_resource.should_not be_updated end it "should raise an exception when deleting a directory when target directory is a file" do stub_file_cstats @new_resource.path "/an/invalid/path" File.stub!(:exists?).and_return(true) File.should_receive(:directory?).and_return(false) Dir.should_not_receive(:delete).with(@new_resource.path) lambda { @directory.run_action(:delete) }.should raise_error(RuntimeError) @directory.new_resource.should_not be_updated end def stub_file_cstats cstats = mock("stats") cstats.stub!(:uid).and_return(500) cstats.stub!(:gid).and_return(500) cstats.stub!(:mode).and_return(0755) # File.stat is called in: # - Chef::Provider::File.load_current_resource_attrs # - Chef::ScanAccessControl via Chef::Provider::File.setup_acl File.stub!(:stat).and_return(cstats) end end chef-11.8.2/spec/unit/provider/deploy/0000755000004100000410000000000012254362222017577 5ustar www-datawww-datachef-11.8.2/spec/unit/provider/deploy/timestamped_spec.rb0000644000004100000410000000264012254362222023454 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Deploy::Timestamped do before do @release_time = Time.utc( 2004, 8, 15, 16, 23, 42) Time.stub!(:now).and_return(@release_time) @expected_release_dir = "/my/deploy/dir/releases/20040815162342" @resource = Chef::Resource::Deploy.new("/my/deploy/dir") @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @timestamped_deploy = Chef::Provider::Deploy::Timestamped.new(@resource, @run_context) @runner = mock("runnah") Chef::Runner.stub!(:new).and_return(@runner) end it "gives a timestamp for release_slug" do @timestamped_deploy.send(:release_slug).should == "20040815162342" end end chef-11.8.2/spec/unit/provider/deploy/revision_spec.rb0000644000004100000410000001020112254362222022766 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Deploy::Revision do before do @temp_dir = Dir.mktmpdir Chef::Config[:file_cache_path] = @temp_dir @resource = Chef::Resource::Deploy.new("/my/deploy/dir") @resource.revision("8a3195bf3efa246f743c5dfa83683201880f935c") @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @provider = Chef::Provider::Deploy::Revision.new(@resource, @run_context) @provider.load_current_resource @runner = mock("runnah") Chef::Runner.stub!(:new).and_return(@runner) @expected_release_dir = "/my/deploy/dir/releases/8a3195bf3efa246f743c5dfa83683201880f935c" end after do # Make sure we don't keep any state in our tests FileUtils.rspec_reset FileUtils.rm_rf @temp_dir if File.directory?( @temp_dir ) end it "uses the resolved revision from the SCM as the release slug" do @provider.scm_provider.stub!(:revision_slug).and_return("uglySlugly") @provider.send(:release_slug).should == "uglySlugly" end it "deploys to a dir named after the revision" do @provider.release_path.should == @expected_release_dir end it "stores the release dir in the file cache in the cleanup step" do FileUtils.stub!(:mkdir_p) FileUtils.stub!(:cp_r) @provider.cleanup! @provider.stub!(:release_slug).and_return("73219b87e977d9c7ba1aa57e9ad1d88fa91a0ec2") @provider.load_current_resource @provider.cleanup! second_release = "/my/deploy/dir/releases/73219b87e977d9c7ba1aa57e9ad1d88fa91a0ec2" @provider.all_releases.should == [@expected_release_dir,second_release] end it "removes a release from the file cache when it's used again in another release and append it to the end" do FileUtils.stub!(:mkdir_p) FileUtils.stub!(:cp_r) @provider.cleanup! @provider.stub!(:release_slug).and_return("73219b87e977d9c7ba1aa57e9ad1d88fa91a0ec2") @provider.load_current_resource @provider.cleanup! second_release = "/my/deploy/dir/releases/73219b87e977d9c7ba1aa57e9ad1d88fa91a0ec2" @provider.all_releases.should == [@expected_release_dir,second_release] @provider.cleanup! @provider.stub!(:release_slug).and_return("8a3195bf3efa246f743c5dfa83683201880f935c") @provider.load_current_resource @provider.cleanup! @provider.all_releases.should == [second_release, @expected_release_dir] end it "removes a release from the file cache when it's deleted by :cleanup!" do release_paths = %w{first second third fourth fifth}.map do |release_name| "/my/deploy/dir/releases/#{release_name}" end release_paths.each do |release_path| @provider.send(:release_created, release_path) end @provider.all_releases.should == release_paths FileUtils.stub!(:rm_rf) @provider.cleanup! expected_release_paths = (%w{second third fourth fifth} << @resource.revision).map do |release_name| "/my/deploy/dir/releases/#{release_name}" end @provider.all_releases.should == expected_release_paths end it "regenerates the file cache if it's not available" do oldest = "/my/deploy/dir/releases/oldest" latest = "/my/deploy/dir/releases/latest" Dir.should_receive(:glob).with("/my/deploy/dir/releases/*").and_return([latest, oldest]) ::File.should_receive(:ctime).with(oldest).and_return(Time.now - 10) ::File.should_receive(:ctime).with(latest).and_return(Time.now - 1) @provider.all_releases.should == [oldest, latest] end end chef-11.8.2/spec/unit/provider/remote_directory_spec.rb0000644000004100000410000002246612254362222023233 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Daniel DeLeo # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'digest/md5' require 'tmpdir' require 'chef/mixin/file_class' class Chef::CFCCheck include Chef::Mixin::FileClass end describe Chef::Provider::RemoteDirectory do before do Chef::FileAccessControl.any_instance.stub(:set_all) @resource = Chef::Resource::RemoteDirectory.new(File.join(Dir.tmpdir, "tafty")) # in CHEF_SPEC_DATA/cookbooks/openldap/files/default/remotedir @resource.source "remotedir" @resource.cookbook('openldap') @cookbook_repo = ::File.expand_path(::File.join(CHEF_SPEC_DATA, "cookbooks")) Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, @cookbook_repo) } @node = Chef::Node.new cl = Chef::CookbookLoader.new(@cookbook_repo) cl.load_cookbooks @cookbook_collection = Chef::CookbookCollection.new(cl) @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) @provider = Chef::Provider::RemoteDirectory.new(@resource, @run_context) @provider.current_resource = @resource.clone end describe "when the contents of the directory changed on the first run and not on the second run" do before do @resource_second_run = @resource.clone @provider_second_run = Chef::Provider::RemoteDirectory.new(@resource_second_run, @run_context) @provider.run_action(:create) @provider_second_run.run_action(:create) end it "identifies that the state has changed the after first run" do @provider_second_run.new_resource.updated_by_last_action? == true end it "identifies that the state has not changed after the second run" do @provider_second_run.new_resource.updated_by_last_action? == false end end describe "when access control is configured on the resource" do before do @resource.mode "0750" @resource.group "wheel" @resource.owner "root" @resource.files_mode "0640" @resource.files_group "staff" @resource.files_owner "toor" @resource.files_backup 23 @resource.source "remotedir_root" end it "configures access control on intermediate directorys" do directory_resource = @provider.send(:resource_for_directory, File.join(Dir.tmpdir, "intermediate_dir")) directory_resource.path.should == File.join(Dir.tmpdir, "intermediate_dir") directory_resource.mode.should == "0750" directory_resource.group.should == "wheel" directory_resource.owner.should == "root" directory_resource.recursive.should be_true end it "configures access control on files in the directory" do @resource.cookbook "berlin_style_tasty_cupcakes" cookbook_file = @provider.send(:cookbook_file_resource, "/target/destination/path.txt", "relative/source/path.txt") cookbook_file.cookbook_name.should == "berlin_style_tasty_cupcakes" cookbook_file.source.should == "remotedir_root/relative/source/path.txt" cookbook_file.mode.should == "0640" cookbook_file.group.should == "staff" cookbook_file.owner.should == "toor" cookbook_file.backup.should == 23 end end describe "when creating the remote directory" do before do @node.automatic_attrs[:platform] = :just_testing @node.automatic_attrs[:platform_version] = :just_testing @destination_dir = Dir.mktmpdir << "/remote_directory_test" @resource.path(@destination_dir) end after {FileUtils.rm_rf(@destination_dir)} # CHEF-3552 it "creates the toplevel directory without error " do @resource.recursive(false) @provider.run_action(:create) ::File.exist?(@destination_dir).should be_true end it "transfers the directory with all contents" do @provider.run_action(:create) ::File.exist?(@destination_dir + '/remote_dir_file1.txt').should be_true ::File.exist?(@destination_dir + '/remote_dir_file2.txt').should be_true ::File.exist?(@destination_dir + '/remotesubdir/remote_subdir_file1.txt').should be_true ::File.exist?(@destination_dir + '/remotesubdir/remote_subdir_file2.txt').should be_true ::File.exist?(@destination_dir + '/remotesubdir/.a_dotfile').should be_true ::File.exist?(@destination_dir + '/.a_dotdir/.a_dotfile_in_a_dotdir').should be_true end describe "only if it is missing" do it "should not overwrite existing files" do @resource.overwrite(true) @provider.run_action(:create) File.open(@destination_dir + '/remote_dir_file1.txt', 'a') {|f| f.puts "blah blah blah" } File.open(@destination_dir + '/remotesubdir/remote_subdir_file1.txt', 'a') {|f| f.puts "blah blah blah" } file1md5 = Digest::MD5.hexdigest(File.read(@destination_dir + '/remote_dir_file1.txt')) subdirfile1md5 = Digest::MD5.hexdigest(File.read(@destination_dir + '/remotesubdir/remote_subdir_file1.txt')) @provider.run_action(:create_if_missing) file1md5.eql?(Digest::MD5.hexdigest(File.read(@destination_dir + '/remote_dir_file1.txt'))).should be_true subdirfile1md5.eql?(Digest::MD5.hexdigest(File.read(@destination_dir + '/remotesubdir/remote_subdir_file1.txt'))).should be_true end end describe "with purging enabled" do before {@resource.purge(true)} it "removes existing files if purge is true" do @provider.run_action(:create) FileUtils.touch(@destination_dir + '/marked_for_death.txt') FileUtils.touch(@destination_dir + '/remotesubdir/marked_for_death_again.txt') @provider.run_action(:create) ::File.exist?(@destination_dir + '/remote_dir_file1.txt').should be_true ::File.exist?(@destination_dir + '/remote_dir_file2.txt').should be_true ::File.exist?(@destination_dir + '/remotesubdir/remote_subdir_file1.txt').should be_true ::File.exist?(@destination_dir + '/remotesubdir/remote_subdir_file2.txt').should be_true ::File.exist?(@destination_dir + '/marked_for_death.txt').should be_false ::File.exist?(@destination_dir + '/remotesubdir/marked_for_death_again.txt').should be_false end it "removes files in subdirectories before files above" do @provider.run_action(:create) FileUtils.mkdir_p(@destination_dir + '/a/multiply/nested/directory/') FileUtils.touch(@destination_dir + '/a/foo.txt') FileUtils.touch(@destination_dir + '/a/multiply/bar.txt') FileUtils.touch(@destination_dir + '/a/multiply/nested/baz.txt') FileUtils.touch(@destination_dir + '/a/multiply/nested/directory/qux.txt') @provider.run_action(:create) ::File.exist?(@destination_dir + '/a/foo.txt').should be_false ::File.exist?(@destination_dir + '/a/multiply/bar.txt').should be_false ::File.exist?(@destination_dir + '/a/multiply/nested/baz.txt').should be_false ::File.exist?(@destination_dir + '/a/multiply/nested/directory/qux.txt').should be_false end it "removes directory symlinks properly", :not_supported_on_win2k3 do symlinked_dir_path = @destination_dir + '/symlinked_dir' @provider.action = :create @provider.run_action @fclass = Chef::CFCCheck.new Dir.mktmpdir do |tmp_dir| begin @fclass.file_class.symlink(tmp_dir.dup, symlinked_dir_path) ::File.exist?(symlinked_dir_path).should be_true @provider.run_action ::File.exist?(symlinked_dir_path).should be_false ::File.exist?(tmp_dir).should be_true rescue Chef::Exceptions::Win32APIError => e pending "This must be run as an Administrator to create symlinks" end end end end describe "with overwrite disabled" do before {@resource.purge(false)} before {@resource.overwrite(false)} it "leaves modifications alone" do @provider.run_action(:create) ::File.open(@destination_dir + '/remote_dir_file1.txt', 'a') {|f| f.puts "blah blah blah" } ::File.open(@destination_dir + '/remotesubdir/remote_subdir_file1.txt', 'a') {|f| f.puts "blah blah blah" } file1md5 = Digest::MD5.hexdigest(::File.read(@destination_dir + '/remote_dir_file1.txt')) subdirfile1md5 = Digest::MD5.hexdigest(::File.read(@destination_dir + '/remotesubdir/remote_subdir_file1.txt')) @provider.run_action(:create) file1md5.eql?(Digest::MD5.hexdigest(::File.read(@destination_dir + '/remote_dir_file1.txt'))).should be_true subdirfile1md5.eql?(Digest::MD5.hexdigest(::File.read(@destination_dir + '/remotesubdir/remote_subdir_file1.txt'))).should be_true end end end end chef-11.8.2/spec/unit/provider/user/0000755000004100000410000000000012254362222017261 5ustar www-datawww-datachef-11.8.2/spec/unit/provider/user/useradd_spec.rb0000644000004100000410000000221012254362222022242 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008, 2010 Opscode, Inc. # # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::User::Useradd do subject(:provider) do p = described_class.new(@new_resource, @run_context) p.current_resource = @current_resource p end supported_useradd_options = { 'comment' => "-c", 'gid' => "-g", 'uid' => "-u", 'shell' => "-s", 'password' => "-p" } include_examples "a useradd-based user provider", supported_useradd_options end chef-11.8.2/spec/unit/provider/user/windows_spec.rb0000644000004100000410000001265612254362222022324 0ustar www-datawww-data# # Author:: Doug MacEachern () # Copyright:: Copyright (c) 2010 VMware, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' class Chef class Util class Windows class NetUser end end end end describe Chef::Provider::User::Windows do before(:each) do @node = Chef::Node.new @new_resource = Chef::Resource::User.new("monkey") @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @current_resource = Chef::Resource::User.new("monkey") @net_user = mock("Chef::Util::Windows::NetUser") Chef::Util::Windows::NetUser.stub!(:new).and_return(@net_user) @provider = Chef::Provider::User::Windows.new(@new_resource, @run_context) @provider.current_resource = @current_resource end describe "when comparing the user's current attributes to the desired attributes" do before do @new_resource.comment "Adam Jacob" @new_resource.uid 1000 @new_resource.gid 1000 @new_resource.home "/home/adam" @new_resource.shell "/usr/bin/zsh" @new_resource.password "abracadabra" @provider.current_resource = @new_resource.clone end describe "and the attributes match" do it "doesn't set the comment field to be updated" do @provider.set_options.should_not have_key(:full_name) end it "doesn't set the home directory to be updated" do @provider.set_options.should_not have_key(:home_dir) end it "doesn't set the group id to be updated" do @provider.set_options.should_not have_key(:primary_group_id) end it "doesn't set the user id to be updated" do @provider.set_options.should_not have_key(:user_id) end it "doesn't set the shell to be updated" do @provider.set_options.should_not have_key(:script_path) end it "doesn't set the password to be updated" do @provider.set_options.should_not have_key(:password) end end describe "and the attributes do not match" do before do @current_resource = Chef::Resource::User.new("adam") @current_resource.comment "Adam Jacob-foo" @current_resource.uid 1111 @current_resource.gid 1111 @current_resource.home "/home/adam-foo" @current_resource.shell "/usr/bin/tcsh" @current_resource.password "foobarbaz" @provider.current_resource = @current_resource end it "marks the full_name field to be updated" do @provider.set_options[:full_name].should == "Adam Jacob" end it "marks the home_dir attribute to be updated" do @provider.set_options[:home_dir].should == '/home/adam' end it "marks the primary_group_id attribute to be updated" do @provider.set_options[:primary_group_id].should == 1000 end it "marks the user_id attribute to be updated" do @provider.set_options[:user_id].should == 1000 end it "marks the script_path attribute to be updated" do @provider.set_options[:script_path].should == '/usr/bin/zsh' end it "marks the password attribute to be updated" do @provider.set_options[:password].should == 'abracadabra' end end end describe "when creating the user" do it "should call @net_user.add with the return of set_options" do @provider.stub!(:set_options).and_return(:name=> "monkey") @net_user.should_receive(:add).with(:name=> "monkey") @provider.create_user end end describe "manage_user" do before(:each) do @provider.stub!(:set_options).and_return(:name=> "monkey") end it "should call @net_user.update with the return of set_options" do @net_user.should_receive(:update).with(:name=> "monkey") @provider.manage_user end end describe "when removing the user" do it "should call @net_user.delete" do @net_user.should_receive(:delete) @provider.remove_user end end describe "when checking if the user is locked" do before(:each) do @current_resource.password "abracadabra" end it "should return true if user is locked" do @net_user.stub!(:check_enabled).and_return(true) @provider.check_lock.should eql(true) end it "should return false if user is not locked" do @net_user.stub!(:check_enabled).and_return(false) @provider.check_lock.should eql(false) end end describe "locking the user" do it "should call @net_user.disable_account" do @net_user.stub!(:check_enabled).and_return(true) @net_user.should_receive(:disable_account) @provider.lock_user end end describe "unlocking the user" do it "should call @net_user.enable_account" do @net_user.stub!(:check_enabled).and_return(false) @net_user.should_receive(:enable_account) @provider.unlock_user end end end chef-11.8.2/spec/unit/provider/user/dscl_spec.rb0000644000004100000410000005066512254362222021561 0ustar www-datawww-data# # Author:: Dreamcat4 () # Copyright:: Copyright (c) 2009 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # ShellCmdResult = Struct.new(:stdout, :stderr, :exitstatus) require 'spec_helper' require 'ostruct' describe Chef::Provider::User::Dscl do before do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::User.new("toor") @provider = Chef::Provider::User::Dscl.new(@new_resource, @run_context) end describe "when shelling out to dscl" do it "should run dscl with the supplied cmd /Path args" do shell_return = ShellCmdResult.new('stdout', 'err', 0) @provider.should_receive(:shell_out).with("dscl . -cmd /Path args").and_return(shell_return) @provider.safe_dscl("cmd /Path args").should == 'stdout' end it "returns an empty string from delete commands" do shell_return = ShellCmdResult.new('out', 'err', 23) @provider.should_receive(:shell_out).with("dscl . -delete /Path args").and_return(shell_return) @provider.safe_dscl("delete /Path args").should == "" end it "should raise an exception for any other command" do shell_return = ShellCmdResult.new('out', 'err', 23) @provider.should_receive(:shell_out).with('dscl . -cmd /Path arguments').and_return(shell_return) lambda { @provider.safe_dscl("cmd /Path arguments") }.should raise_error(Chef::Exceptions::DsclCommandFailed) end it "raises an exception when dscl reports 'no such key'" do shell_return = ShellCmdResult.new("No such key: ", 'err', 23) @provider.should_receive(:shell_out).with('dscl . -cmd /Path args').and_return(shell_return) lambda { @provider.safe_dscl("cmd /Path args") }.should raise_error(Chef::Exceptions::DsclCommandFailed) end it "raises an exception when dscl reports 'eDSRecordNotFound'" do shell_return = ShellCmdResult.new(" DS Error: -14136 (eDSRecordNotFound)", 'err', -14136) @provider.should_receive(:shell_out).with('dscl . -cmd /Path args').and_return(shell_return) lambda { @provider.safe_dscl("cmd /Path args") }.should raise_error(Chef::Exceptions::DsclCommandFailed) end end describe "get_free_uid" do before do @provider.stub!(:safe_dscl).and_return("\nwheel 200\nstaff 201\n") end it "should run safe_dscl with list /Users uid" do @provider.should_receive(:safe_dscl).with("list /Users uid") @provider.get_free_uid end it "should return the first unused uid number on or above 200" do @provider.get_free_uid.should == 202 end it "should raise an exception when the search limit is exhausted" do search_limit = 1 lambda { @provider.get_free_uid(search_limit) }.should raise_error(RuntimeError) end end describe "uid_used?" do before do @provider.stub!(:safe_dscl).and_return("\naj 500\n") end it "should run safe_dscl with list /Users uid" do @provider.should_receive(:safe_dscl).with("list /Users uid") @provider.uid_used?(500) end it "should return true for a used uid number" do @provider.uid_used?(500).should be_true end it "should return false for an unused uid number" do @provider.uid_used?(501).should be_false end it "should return false if not given any valid uid number" do @provider.uid_used?(nil).should be_false end end describe "when determining the uid to set" do it "raises RequestedUIDUnavailable if the requested uid is already in use" do @provider.stub!(:uid_used?).and_return(true) @provider.should_receive(:get_free_uid).and_return(501) lambda { @provider.set_uid }.should raise_error(Chef::Exceptions::RequestedUIDUnavailable) end it "finds a valid, unused uid when none is specified" do @provider.should_receive(:safe_dscl).with("list /Users uid").and_return('') @provider.should_receive(:safe_dscl).with("create /Users/toor UniqueID 501") @provider.should_receive(:get_free_uid).and_return(501) @provider.set_uid @new_resource.uid.should == 501 end it "sets the uid specified in the resource" do @new_resource.uid(1000) @provider.should_receive(:safe_dscl).with("create /Users/toor UniqueID 1000").and_return(true) @provider.should_receive(:safe_dscl).with("list /Users uid").and_return('') @provider.set_uid end end describe "when modifying the home directory" do before do @new_resource.supports({ :manage_home => true }) @new_resource.home('/Users/toor') @current_resource = @new_resource.dup @provider.current_resource = @current_resource end it "deletes the home directory when resource#home is nil" do @new_resource.instance_variable_set(:@home, nil) @provider.should_receive(:safe_dscl).with("delete /Users/toor NFSHomeDirectory").and_return(true) @provider.modify_home end it "raises InvalidHomeDirectory when the resource's home directory doesn't look right" do @new_resource.home('epic-fail') lambda { @provider.modify_home }.should raise_error(Chef::Exceptions::InvalidHomeDirectory) end it "moves the users home to the new location if it exists and the target location is different" do @new_resource.supports(:manage_home => true) current_home = CHEF_SPEC_DATA + '/old_home_dir' current_home_files = [current_home + '/my-dot-emacs', current_home + '/my-dot-vim'] @current_resource.home(current_home) @new_resource.gid(23) ::File.stub!(:exists?).with('/old/home/toor').and_return(true) ::File.stub!(:exists?).with('/Users/toor').and_return(true) FileUtils.should_receive(:mkdir_p).with('/Users/toor').and_return(true) FileUtils.should_receive(:rmdir).with(current_home) ::Dir.should_receive(:glob).with("#{CHEF_SPEC_DATA}/old_home_dir/*",::File::FNM_DOTMATCH).and_return(current_home_files) FileUtils.should_receive(:mv).with(current_home_files, "/Users/toor", :force => true) FileUtils.should_receive(:chown_R).with('toor','23','/Users/toor') @provider.should_receive(:safe_dscl).with("create /Users/toor NFSHomeDirectory '/Users/toor'") @provider.modify_home end it "should raise an exception when the systems user template dir (skel) cannot be found" do ::File.stub!(:exists?).and_return(false,false,false) lambda { @provider.modify_home }.should raise_error(Chef::Exceptions::User) end it "should run ditto to copy any missing files from skel to the new home dir" do ::File.should_receive(:exists?).with("/System/Library/User\ Template/English.lproj").and_return(true) FileUtils.should_receive(:chown_R).with('toor', '', '/Users/toor') @provider.should_receive(:shell_out!).with("ditto '/System/Library/User Template/English.lproj' '/Users/toor'") @provider.ditto_home end it "creates the user's NFSHomeDirectory and home directory" do @provider.should_receive(:safe_dscl).with("create /Users/toor NFSHomeDirectory '/Users/toor'").and_return(true) @provider.should_receive(:ditto_home) @provider.modify_home end end describe "osx_shadow_hash?" do it "should return true when the string is a shadow hash" do @provider.osx_shadow_hash?("0"*8*155).should eql(true) end it "should return false otherwise" do @provider.osx_shadow_hash?("any other string").should eql(false) end end describe "when detecting the format of a password" do it "detects a OS X salted sha1" do @provider.osx_salted_sha1?("0"*48).should eql(true) @provider.osx_salted_sha1?("any other string").should eql(false) end end describe "guid" do it "should run safe_dscl with read /Users/user GeneratedUID to get the users GUID" do expected_uuid = "b398449e-cee0-45e0-80f8-b0b5b1bfdeaa" @provider.should_receive(:safe_dscl).with("read /Users/toor GeneratedUID").and_return(expected_uuid + "\n") @provider.guid.should == expected_uuid end end describe "shadow_hash_set?" do it "should run safe_dscl with read /Users/user to see if the AuthenticationAuthority key exists" do @provider.should_receive(:safe_dscl).with("read /Users/toor") @provider.shadow_hash_set? end describe "when the user account has an AuthenticationAuthority key" do it "uses the shadow hash when there is a ShadowHash field in the AuthenticationAuthority key" do @provider.should_receive(:safe_dscl).with("read /Users/toor").and_return("\nAuthenticationAuthority: ;ShadowHash;\n") @provider.shadow_hash_set?.should be_true end it "does not use the shadow hash when there is no ShadowHash field in the AuthenticationAuthority key" do @provider.should_receive(:safe_dscl).with("read /Users/toor").and_return("\nAuthenticationAuthority: \n") @provider.shadow_hash_set?.should be_false end end describe "with no AuthenticationAuthority key in the user account" do it "does not use the shadow hash" do @provider.should_receive(:safe_dscl).with("read /Users/toor").and_return("") @provider.shadow_hash_set?.should eql(false) end end end describe "when setting or modifying the user password" do before do @new_resource.password("password") @output = StringIO.new end describe "when using a salted sha1 for the password" do before do @new_resource.password("F"*48) end it "should write a shadow hash file with the expected salted sha1" do uuid = "B398449E-CEE0-45E0-80F8-B0B5B1BFDEAA" File.should_receive(:open).with('/var/db/shadow/hash/B398449E-CEE0-45E0-80F8-B0B5B1BFDEAA', "w", 384).and_yield(@output) @provider.should_receive(:safe_dscl).with("read /Users/toor GeneratedUID").and_return(uuid) @provider.should_receive(:safe_dscl).with("read /Users/toor").and_return("\nAuthenticationAuthority: ;ShadowHash;\n") expected_salted_sha1 = @new_resource.password expected_shadow_hash = "00000000"*155 expected_shadow_hash[168] = expected_salted_sha1 @provider.modify_password @output.string.strip.should == expected_shadow_hash end end describe "when given a shadow hash file for the password" do it "should write the shadow hash file directly to /var/db/shadow/hash/GUID" do shadow_hash = '0123456789ABCDE0123456789ABCDEF' * 40 raise 'oops' unless shadow_hash.size == 1240 @new_resource.password shadow_hash uuid = "B398449E-CEE0-45E0-80F8-B0B5B1BFDEAA" File.should_receive(:open).with('/var/db/shadow/hash/B398449E-CEE0-45E0-80F8-B0B5B1BFDEAA', "w", 384).and_yield(@output) @provider.should_receive(:safe_dscl).with("read /Users/toor GeneratedUID").and_return(uuid) @provider.should_receive(:safe_dscl).with("read /Users/toor").and_return("\nAuthenticationAuthority: ;ShadowHash;\n") @provider.modify_password @output.string.strip.should == shadow_hash end end describe "when given a string for the password" do it "should output a salted sha1 and shadow hash file from the specified password" do uuid = "B398449E-CEE0-45E0-80F8-B0B5B1BFDEAA" File.should_receive(:open).with('/var/db/shadow/hash/B398449E-CEE0-45E0-80F8-B0B5B1BFDEAA', "w", 384).and_yield(@output) @new_resource.password("password") OpenSSL::Random.stub!(:random_bytes).and_return("\377\377\377\377\377\377\377\377") expected_salted_sha1 = "F"*8+"SHA1-"*8 expected_shadow_hash = "00000000"*155 expected_shadow_hash[168] = expected_salted_sha1 @provider.should_receive(:safe_dscl).with("read /Users/toor GeneratedUID").and_return(uuid) @provider.should_receive(:safe_dscl).with("read /Users/toor").and_return("\nAuthenticationAuthority: ;ShadowHash;\n") @provider.modify_password @output.string.strip.should match(/^0{168}(FFFFFFFF1C1AA7935D4E1190AFEC92343F31F7671FBF126D)0{1071}$/) end end it "should write the output directly to the shadow hash file at /var/db/shadow/hash/GUID" do shadow_file = StringIO.new uuid = "B398449E-CEE0-45E0-80F8-B0B5B1BFDEAA" File.should_receive(:open).with("/var/db/shadow/hash/B398449E-CEE0-45E0-80F8-B0B5B1BFDEAA",'w',0600).and_yield(shadow_file) @provider.should_receive(:safe_dscl).with("read /Users/toor GeneratedUID").and_return(uuid) @provider.should_receive(:safe_dscl).with("read /Users/toor").and_return("\nAuthenticationAuthority: ;ShadowHash;\n") @provider.modify_password shadow_file.string.should match(/^0{168}[0-9A-F]{48}0{1071}$/) end it "should run safe_dscl append /Users/user AuthenticationAuthority ;ShadowHash; when no shadow hash set" do shadow_file = StringIO.new uuid = "B398449E-CEE0-45E0-80F8-B0B5B1BFDEAA" File.should_receive(:open).with("/var/db/shadow/hash/B398449E-CEE0-45E0-80F8-B0B5B1BFDEAA",'w',0600).and_yield(shadow_file) @provider.should_receive(:safe_dscl).with("read /Users/toor GeneratedUID").and_return(uuid) @provider.should_receive(:safe_dscl).with("read /Users/toor").and_return("\nAuthenticationAuthority:\n") @provider.should_receive(:safe_dscl).with("append /Users/toor AuthenticationAuthority ';ShadowHash;'") @provider.modify_password shadow_file.string.should match(/^0{168}[0-9A-F]{48}0{1071}$/) end end describe "load_current_resource" do it "should raise an error if the required binary /usr/bin/dscl doesn't exist" do ::File.should_receive(:exists?).with("/usr/bin/dscl").and_return(false) lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::User) end it "shouldn't raise an error if /usr/bin/dscl exists" do ::File.stub!(:exists?).and_return(true) lambda { @provider.load_current_resource }.should_not raise_error(Chef::Exceptions::User) end end describe "when the user does not yet exist and chef is creating it" do context "with a numeric gid" do before do @new_resource.comment "#mockssuck" @new_resource.gid 1001 end it "creates the user, comment field, sets uid, gid, configures the home directory, sets the shell, and sets the password" do @provider.should_receive :dscl_create_user @provider.should_receive :dscl_create_comment @provider.should_receive :set_uid @provider.should_receive :dscl_set_gid @provider.should_receive :modify_home @provider.should_receive :dscl_set_shell @provider.should_receive :modify_password @provider.create_user end it "creates the user and sets the comment field" do @provider.should_receive(:safe_dscl).with("create /Users/toor").and_return(true) @provider.dscl_create_user end it "sets the comment field" do @provider.should_receive(:safe_dscl).with("create /Users/toor RealName '#mockssuck'").and_return(true) @provider.dscl_create_comment end it "should run safe_dscl with create /Users/user PrimaryGroupID to set the users primary group" do @provider.should_receive(:safe_dscl).with("create /Users/toor PrimaryGroupID '1001'").and_return(true) @provider.dscl_set_gid end it "should run safe_dscl with create /Users/user UserShell to set the users login shell" do @provider.should_receive(:safe_dscl).with("create /Users/toor UserShell '/usr/bin/false'").and_return(true) @provider.dscl_set_shell end end context "with a non-numeric gid" do before do @new_resource.comment "#mockssuck" @new_resource.gid "newgroup" end it "should map the group name to a numeric ID when the group exists" do @provider.should_receive(:safe_dscl).with("read /Groups/newgroup PrimaryGroupID").ordered.and_return("PrimaryGroupID: 1001\n") @provider.should_receive(:safe_dscl).with("create /Users/toor PrimaryGroupID '1001'").ordered.and_return(true) @provider.dscl_set_gid end it "should raise an exception when the group does not exist" do shell_return = ShellCmdResult.new(" DS Error: -14136 (eDSRecordNotFound)", 'err', -14136) @provider.should_receive(:shell_out).with('dscl . -read /Groups/newgroup PrimaryGroupID').and_return(shell_return) lambda { @provider.dscl_set_gid }.should raise_error(Chef::Exceptions::GroupIDNotFound) end end end describe "when the user exists and chef is managing it" do before do @current_resource = @new_resource.dup @provider.current_resource = @current_resource # These are all different from @current_resource @new_resource.username "mud" @new_resource.uid 2342 @new_resource.gid 2342 @new_resource.home '/Users/death' @new_resource.password 'goaway' end it "sets the user, comment field, uid, gid, moves the home directory, sets the shell, and sets the password" do @provider.should_receive :dscl_create_user @provider.should_receive :dscl_create_comment @provider.should_receive :set_uid @provider.should_receive :dscl_set_gid @provider.should_receive :modify_home @provider.should_receive :dscl_set_shell @provider.should_receive :modify_password @provider.create_user end end describe "when changing the gid" do before do @current_resource = @new_resource.dup @provider.current_resource = @current_resource # This is different from @current_resource @new_resource.gid 2342 end it "sets the gid" do @provider.should_receive :dscl_set_gid @provider.manage_user end end describe "when the user exists and chef is removing it" do it "removes the user's home directory when the resource is configured to manage home" do @new_resource.supports({ :manage_home => true }) @provider.should_receive(:safe_dscl).with("read /Users/toor").and_return("NFSHomeDirectory: /Users/fuuuuuuuuuuuuu") @provider.should_receive(:safe_dscl).with("delete /Users/toor") FileUtils.should_receive(:rm_rf).with("/Users/fuuuuuuuuuuuuu") @provider.remove_user end it "removes the user from any group memberships" do Etc.stub(:group).and_yield(OpenStruct.new(:name => 'ragefisters', :mem => 'toor')) @provider.should_receive(:safe_dscl).with("delete /Users/toor") @provider.should_receive(:safe_dscl).with("delete /Groups/ragefisters GroupMembership 'toor'") @provider.remove_user end end describe "when discovering if a user is locked" do it "determines the user is not locked when dscl shows an AuthenticationAuthority without a DisabledUser field" do @provider.should_receive(:safe_dscl).with("read /Users/toor") @provider.should_not be_locked end it "determines the user is locked when dscl shows an AuthenticationAuthority with a DisabledUser field" do @provider.should_receive(:safe_dscl).with('read /Users/toor').and_return("\nAuthenticationAuthority: ;DisabledUser;\n") @provider.should be_locked end it "determines the user is not locked when dscl shows no AuthenticationAuthority" do @provider.should_receive(:safe_dscl).with('read /Users/toor').and_return("\n") @provider.should_not be_locked end end describe "when locking the user" do it "should run safe_dscl with append /Users/user AuthenticationAuthority ;DisabledUser; to lock the user account" do @provider.should_receive(:safe_dscl).with("append /Users/toor AuthenticationAuthority ';DisabledUser;'") @provider.lock_user end end describe "when unlocking the user" do it "removes DisabledUser from the authentication string" do @provider.should_receive(:safe_dscl).with("read /Users/toor AuthenticationAuthority").and_return("\nAuthenticationAuthority: ;ShadowHash; ;DisabledUser;\n") @provider.should_receive(:safe_dscl).with("create /Users/toor AuthenticationAuthority ';ShadowHash;'") @provider.unlock_user end end end chef-11.8.2/spec/unit/provider/user/solaris_spec.rb0000644000004100000410000000510412254362222022274 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008, 2010 Opscode, Inc. # # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::User::Solaris do subject(:provider) do p = described_class.new(@new_resource, @run_context) p.current_resource = @current_resource # Prevent the useradd-based provider tests from trying to write /etc/shadow p.stub!(:write_shadow_file) p end supported_useradd_options = { 'comment' => "-c", 'gid' => "-g", 'uid' => "-u", 'shell' => "-s" } include_examples "a useradd-based user provider", supported_useradd_options describe "when we want to set a password" do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::User.new("adam", @run_context) @current_resource = Chef::Resource::User.new("adam", @run_context) @new_resource.password "hocus-pocus" # Let these tests run #write_shadow_file provider.unstub!(:write_shadow_file) end it "should use its own shadow file writer to set the password" do provider.should_receive(:write_shadow_file) provider.stub!(:shell_out!).and_return(true) provider.manage_user end it "should write out a modified version of the password file" do password_file = Tempfile.new("shadow") password_file.puts "adam:existingpassword:15441::::::" password_file.close provider.password_file = password_file.path provider.stub!(:shell_out!).and_return(true) # may not be able to write to /etc for tests... temp_file = Tempfile.new("shadow") Tempfile.stub!(:new).with("shadow", "/etc").and_return(temp_file) @new_resource.password "verysecurepassword" provider.manage_user ::File.open(password_file.path, "r").read.should =~ /adam:verysecurepassword:/ password_file.unlink end end end chef-11.8.2/spec/unit/provider/user/pw_spec.rb0000644000004100000410000002053712254362222021255 0ustar www-datawww-data# # Author:: Stephen Haynes () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::User::Pw do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::User.new("adam") @new_resource.comment "Adam Jacob" @new_resource.uid 1000 @new_resource.gid 1000 @new_resource.home "/home/adam" @new_resource.shell "/usr/bin/zsh" @new_resource.password "abracadabra" @new_resource.supports :manage_home => true @current_resource = Chef::Resource::User.new("adam") @current_resource.comment "Adam Jacob" @current_resource.uid 1000 @current_resource.gid 1000 @current_resource.home "/home/adam" @current_resource.shell "/usr/bin/zsh" @current_resource.password "abracadabra" @provider = Chef::Provider::User::Pw.new(@new_resource, @run_context) @provider.current_resource = @current_resource end describe "setting options to the pw command" do field_list = { 'comment' => "-c", 'home' => "-d", 'gid' => "-g", 'uid' => "-u", 'shell' => "-s" } field_list.each do |attribute, option| it "should check for differences in #{attribute} between the new and current resources" do @current_resource.should_receive(attribute) @new_resource.should_receive(attribute) @provider.set_options end it "should set the option for #{attribute} if the new resources #{attribute} is not null" do @new_resource.stub!(attribute).and_return("hola") @provider.set_options.should eql(" #{@new_resource.username} #{option} '#{@new_resource.send(attribute)}' -m") end it "should set the option for #{attribute} if the new resources #{attribute} is not null, without homedir management" do @new_resource.stub!(:supports).and_return({:manage_home => false}) @new_resource.stub!(attribute).and_return("hola") @provider.set_options.should eql(" #{@new_resource.username} #{option} '#{@new_resource.send(attribute)}'") end end it "should combine all the possible options" do match_string = " adam" field_list.sort{ |a,b| a[0] <=> b[0] }.each do |attribute, option| @new_resource.stub!(attribute).and_return("hola") match_string << " #{option} 'hola'" end match_string << " -m" @provider.set_options.should eql(match_string) end end describe "create_user" do before(:each) do @provider.stub!(:run_command).and_return(true) @provider.stub!(:modify_password).and_return(true) end it "should run pw useradd with the return of set_options" do @provider.should_receive(:run_command).with({ :command => "pw useradd adam -m" }).and_return(true) @provider.create_user end it "should modify the password" do @provider.should_receive(:modify_password).and_return(true) @provider.create_user end end describe "manage_user" do before(:each) do @provider.stub!(:run_command).and_return(true) @provider.stub!(:modify_password).and_return(true) end it "should run pw usermod with the return of set_options" do @provider.should_receive(:run_command).with({ :command => "pw usermod adam -m" }).and_return(true) @provider.manage_user end it "should modify the password" do @provider.should_receive(:modify_password).and_return(true) @provider.create_user end end describe "remove_user" do it "should run pw userdel with the new resources user name" do @new_resource.supports :manage_home => false @provider.should_receive(:run_command).with({ :command => "pw userdel #{@new_resource.username}" }).and_return(true) @provider.remove_user end it "should run pw userdel with the new resources user name and -r if manage_home is true" do @provider.should_receive(:run_command).with({ :command => "pw userdel #{@new_resource.username} -r"}).and_return(true) @provider.remove_user end end describe "determining if the user is locked" do it "should return true if user is locked" do @current_resource.stub!(:password).and_return("*LOCKED*abracadabra") @provider.check_lock.should eql(true) end it "should return false if user is not locked" do @current_resource.stub!(:password).and_return("abracadabra") @provider.check_lock.should eql(false) end end describe "when locking the user" do it "should run pw lock with the new resources username" do @provider.should_receive(:run_command).with({ :command => "pw lock #{@new_resource.username}"}) @provider.lock_user end end describe "when unlocking the user" do it "should run pw unlock with the new resources username" do @provider.should_receive(:run_command).with({ :command => "pw unlock #{@new_resource.username}"}) @provider.unlock_user end end describe "when modifying the password" do before(:each) do @status = mock("Status", :exitstatus => 0) @provider.stub!(:popen4).and_return(@status) @pid, @stdin, @stdout, @stderr = nil, nil, nil, nil end it "should check for differences in password between the new and current resources" do @current_resource.should_receive(:password) @new_resource.should_receive(:password) @provider.modify_password end describe "and the passwords are identical" do before(:each) do @new_resource.stub!(:password).and_return("abracadabra") @current_resource.stub!(:password).and_return("abracadabra") end it "logs an appropriate message" do Chef::Log.should_receive(:debug).with("user[adam] no change needed to password") @provider.modify_password end end describe "and the passwords are different" do before(:each) do @new_resource.stub!(:password).and_return("abracadabra") @current_resource.stub!(:password).and_return("sesame") end it "should log an appropriate message" do Chef::Log.should_receive(:debug).with("user[adam] updating password") @provider.modify_password end it "should run pw usermod with the username and the option -H 0" do @provider.should_receive(:popen4).with("pw usermod adam -H 0", :waitlast => true).and_return(@status) @provider.modify_password end it "should send the new password to the stdin of pw usermod" do @stdin = StringIO.new @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.modify_password @stdin.string.should == "abracadabra\n" end it "should raise an exception if pw usermod fails" do @status.should_receive(:exitstatus).and_return(1) lambda { @provider.modify_password }.should raise_error(Chef::Exceptions::User) end it "should not raise an exception if pw usermod succeeds" do @status.should_receive(:exitstatus).and_return(0) lambda { @provider.modify_password }.should_not raise_error(Chef::Exceptions::User) end end end describe "when loading the current state" do before do @provider.new_resource = Chef::Resource::User.new("adam") end it "should raise an error if the required binary /usr/sbin/pw doesn't exist" do File.should_receive(:exists?).with("/usr/sbin/pw").and_return(false) lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::User) end it "shouldn't raise an error if /usr/sbin/pw exists" do File.stub!(:exists?).and_return(true) lambda { @provider.load_current_resource }.should_not raise_error(Chef::Exceptions::User) end end end chef-11.8.2/spec/unit/provider/remote_file_spec.rb0000644000004100000410000000375512254362222022146 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2008-2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'support/shared/unit/provider/file' describe Chef::Provider::RemoteFile do let(:resource) do resource = Chef::Resource::RemoteFile.new("seattle", @run_context) resource.path(resource_path) resource.source("http://foo") resource.cookbook_name = "monkey" resource end let(:content) do content = mock('Chef::Provider::File::Content::RemoteFile') end let(:node) { double('Chef::Node') } let(:events) { double('Chef::Events').as_null_object } # mock all the methods let(:run_context) { double('Chef::RunContext', :node => node, :events => events) } let(:enclosing_directory) { canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates"))) } let(:resource_path) { canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt"))) } subject(:provider) do provider = described_class.new(resource, run_context) provider.stub!(:content).and_return(content) provider.stub!(:update_new_resource_checksum).and_return(nil) # Otherwise it doesn't behave like a File provider provider end before do Chef::FileCache.stub!(:load).with("remote_file/#{resource.name}").and_raise(Chef::Exceptions::FileNotFound) end it_behaves_like Chef::Provider::File end chef-11.8.2/spec/unit/provider/breakpoint_spec.rb0000644000004100000410000000345112254362222022003 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Breakpoint do before do @resource = Chef::Resource::Breakpoint.new @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @collection = mock("resource collection") @run_context.stub!(:resource_collection).and_return(@collection) @provider = Chef::Provider::Breakpoint.new(@resource, @run_context) end it "responds to load_current_resource" do @provider.should respond_to(:load_current_resource) end it "gets the iterator from @collection and pauses it" do Shell.stub!(:running?).and_return(true) @iterator = mock("stepable_iterator") @collection.stub!(:iterator).and_return(@iterator) @iterator.should_receive(:pause) @provider.action_break @resource.should be_updated end it "doesn't pause the iterator if chef-shell isn't running" do Shell.stub!(:running?).and_return(false) @iterator = mock("stepable_iterator") @collection.stub!(:iterator).and_return(@iterator) @iterator.should_not_receive(:pause) @provider.action_break end end chef-11.8.2/spec/unit/provider/log_spec.rb0000644000004100000410000000613112254362222020424 0ustar www-datawww-data# # Author:: Cary Penniman () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Log::ChefLog do before(:each) do @log_str = "this is my test string to log" @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) end it "should be registered with the default platform hash" do Chef::Platform.platforms[:default][:log].should_not be_nil end it "should write the string to the Chef::Log object at default level (info)" do @new_resource = Chef::Resource::Log.new(@log_str) @provider = Chef::Provider::Log::ChefLog.new(@new_resource, @run_context) Chef::Log.should_receive(:info).with(@log_str).and_return(true) @provider.action_write end it "should write the string to the Chef::Log object at debug level" do @new_resource = Chef::Resource::Log.new(@log_str) @new_resource.level :debug @provider = Chef::Provider::Log::ChefLog.new(@new_resource, @run_context) Chef::Log.should_receive(:debug).with(@log_str).and_return(true) @provider.action_write end it "should write the string to the Chef::Log object at info level" do @new_resource = Chef::Resource::Log.new(@log_str) @new_resource.level :info @provider = Chef::Provider::Log::ChefLog.new(@new_resource, @run_context) Chef::Log.should_receive(:info).with(@log_str).and_return(true) @provider.action_write end it "should write the string to the Chef::Log object at warn level" do @new_resource = Chef::Resource::Log.new(@log_str) @new_resource.level :warn @provider = Chef::Provider::Log::ChefLog.new(@new_resource, @run_context) Chef::Log.should_receive(:warn).with(@log_str).and_return(true) @provider.action_write end it "should write the string to the Chef::Log object at error level" do @new_resource = Chef::Resource::Log.new(@log_str) @new_resource.level :error @provider = Chef::Provider::Log::ChefLog.new(@new_resource, @run_context) Chef::Log.should_receive(:error).with(@log_str).and_return(true) @provider.action_write end it "should write the string to the Chef::Log object at fatal level" do @new_resource = Chef::Resource::Log.new(@log_str) @new_resource.level :fatal @provider = Chef::Provider::Log::ChefLog.new(@new_resource, @run_context) Chef::Log.should_receive(:fatal).with(@log_str).and_return(true) @provider.action_write end end chef-11.8.2/spec/unit/provider/mount/0000755000004100000410000000000012254362222017445 5ustar www-datawww-datachef-11.8.2/spec/unit/provider/mount/windows_spec.rb0000644000004100000410000001066012254362222022501 0ustar www-datawww-data# # Author:: Doug MacEachern () # Copyright:: Copyright (c) 2010 VMware, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' class Chef class Util class Windows class NetUse end class Volume end end end end GUID = "\\\\?\\Volume{578e72b5-6e70-11df-b5c5-000c29d4a7d9}\\" REMOTE = "\\\\server-name\\path" describe Chef::Provider::Mount::Windows do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Mount.new("X:") @new_resource.device GUID @current_resource = Chef::Resource::Mount.new("X:") Chef::Resource::Mount.stub!(:new).and_return(@current_resource) @net_use = mock("Chef::Util::Windows::NetUse") Chef::Util::Windows::NetUse.stub!(:new).and_return(@net_use) @vol = mock("Chef::Util::Windows::Volume") Chef::Util::Windows::Volume.stub!(:new).and_return(@vol) @provider = Chef::Provider::Mount::Windows.new(@new_resource, @run_context) @provider.current_resource = @current_resource end describe "when loading the current resource" do it "should set mounted true if the mount point is found" do @vol.stub!(:device).and_return(@new_resource.device) @current_resource.should_receive(:mounted).with(true) @provider.load_current_resource end it "should set mounted false if the mount point is not found" do @vol.stub!(:device).and_raise(ArgumentError) @current_resource.should_receive(:mounted).with(false) @provider.load_current_resource end describe "with a local device" do before do @new_resource.device GUID @vol.stub!(:device).and_return(@new_resource.device) @net_use.stub!(:device).and_raise(ArgumentError) end it "should determine the device is a volume GUID" do @provider.should_receive(:is_volume).with(@new_resource.device).and_return(true) @provider.load_current_resource end end describe "with a remote device" do before do @new_resource.device REMOTE @net_use.stub!(:device).and_return(@new_resource.device) @vol.stub!(:device).and_raise(ArgumentError) end it "should determine the device is remote" do @provider.should_receive(:is_volume).with(@new_resource.device).and_return(false) @provider.load_current_resource end end describe "when mounting a file system" do before do @new_resource.device GUID @vol.stub!(:add) @vol.stub!(:device).and_raise(ArgumentError) @provider.load_current_resource end it "should mount the filesystem if it is not mounted" do @vol.should_receive(:add).with(:remote => @new_resource.device, :username => @new_resource.username, :domainname => @new_resource.domain, :password => @new_resource.password) @provider.mount_fs end it "should not mount the filesystem if it is mounted" do @vol.should_not_receive(:add) @current_resource.stub!(:mounted).and_return(true) @provider.mount_fs end end describe "when unmounting a file system" do before do @new_resource.device GUID @vol.stub!(:delete) @vol.stub!(:device).and_raise(ArgumentError) @provider.load_current_resource end it "should umount the filesystem if it is mounted" do @current_resource.stub!(:mounted).and_return(true) @vol.should_receive(:delete) @provider.umount_fs end it "should not umount the filesystem if it is not mounted" do @current_resource.stub!(:mounted).and_return(false) @vol.should_not_receive(:delete) @provider.umount_fs end end end end chef-11.8.2/spec/unit/provider/mount/aix_spec.rb0000644000004100000410000001766612254362222021605 0ustar www-datawww-data# # Author:: Kaustubh Deorukhkar () # Copyright:: Copyright (c) 2013 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'ostruct' describe Chef::Provider::Mount::Aix do before(:all) do @mounted_output = <<-MOUNT node mounted mounted over vfs date options -------- --------------- --------------- ------ ------------ --------------- /dev/sdz1 /tmp/foo jfs2 Jul 17 13:22 rw,log=/dev/hd8 MOUNT @unmounted_output = <<-UNMOUNTED node mounted mounted over vfs date options -------- --------------- --------------- ------ ------------ --------------- /dev/sdz2 / jfs2 Jul 17 13:22 rw,log=/dev/hd8 UNMOUNTED @conflict_mounted_output = <<-MOUNT node mounted mounted over vfs date options -------- --------------- --------------- ------ ------------ --------------- /dev/sdz3 /tmp/foo jfs2 Jul 17 13:22 rw,log=/dev/hd8 MOUNT @enabled_output = <<-ENABLED #MountPoint:Device:Vfs:Nodename:Type:Size:Options:AutoMount:Acct /tmp/foo:/dev/sdz1:jfs2::bootfs:10485760:rw:yes:no ENABLED end before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Mount.new("/tmp/foo") @new_resource.device "/dev/sdz1" @new_resource.device_type :device @new_resource.fstype "jfs2" @new_resource.supports :remount => false @provider = Chef::Provider::Mount::Aix.new(@new_resource, @run_context) ::File.stub!(:exists?).with("/dev/sdz1").and_return true ::File.stub!(:exists?).with("/tmp/foo").and_return true end def stub_mounted(provider, mounted_output) response = double("Mixlib::ShellOut command", :exitstatus => 0, :stdout => mounted_output, :stderr => "") provider.should_receive(:shell_out!).with("mount").and_return(response) end def stub_enabled(provider, enabled_output) response = double("Mixlib::ShellOut command", :exitstatus => 0, :stdout => enabled_output, :stderr => "") provider.should_receive(:shell_out).with("lsfs -c #{@new_resource.mount_point}").and_return(response) end def stub_mounted_enabled(provider, mounted_output, enabled_output) stub_mounted(provider, mounted_output) stub_enabled(provider, enabled_output) end describe "when discovering the current fs state" do it "should set current_resource.mounted to true if device is already mounted" do stub_mounted_enabled(@provider, @mounted_output, "") @provider.load_current_resource expect(@provider.current_resource.mounted).to be_true end it "should set current_resource.mounted to false if device is not mounted" do stub_mounted_enabled(@provider, @unmounted_output, "") @provider.load_current_resource expect(@provider.current_resource.mounted).to be_false end it "should set current_resource.mounted to false if the mount point is used for another device" do stub_mounted_enabled(@provider, @conflict_mounted_output, "") @provider.load_current_resource expect(@provider.current_resource.mounted).to be_false end end # tests for #enabled? it "should load current_resource with properties if device is already mounted and enabled" do stub_mounted_enabled(@provider, @mounted_output, @enabled_output) @provider.load_current_resource expect(@provider.current_resource.enabled).to be_true expect(@provider.current_resource.mounted).to be_true expect(@provider.current_resource.mount_point).to eql(@new_resource.mount_point) expect(@provider.current_resource.fstype).to eql("jfs2") expect(@provider.current_resource.options).to eql(['rw']) end describe "mount_fs" do it "should mount resource if it is not mounted" do stub_mounted_enabled(@provider, @unmounted_output, "") @provider.should_receive(:shell_out!).with("mount -v #{@new_resource.fstype} #{@new_resource.device} #{@new_resource.mount_point}") @provider.run_action(:mount) end it "should not mount resource if it is already mounted" do stub_mounted_enabled(@provider, @mounted_output, "") @provider.should_not_receive(:mount_fs) @provider.run_action(:mount) end end describe "umount_fs" do it "should umount resource if it is already mounted" do stub_mounted_enabled(@provider, @mounted_output, "") @provider.should_receive(:shell_out!).with("umount #{@new_resource.mount_point}") @provider.run_action(:umount) end it "should not umount resource if it is not mounted" do stub_mounted_enabled(@provider, @unmounted_output, "") @provider.should_not_receive(:umount_fs) @provider.run_action(:umount) end end describe "remount_fs" do it "should remount resource if it is already mounted and it supports remounting" do @new_resource.supports({:remount => true}) stub_mounted_enabled(@provider, @mounted_output, "") @provider.should_receive(:shell_out!).with("mount -o remount #{@new_resource.device} #{@new_resource.mount_point}") @provider.run_action(:remount) end it "should remount with new mount options if it is already mounted and it supports remounting" do @new_resource.supports({:remount => true}) @new_resource.options("nodev,rw") stub_mounted_enabled(@provider, @mounted_output, "") @provider.should_receive(:shell_out!).with("mount -o remount,nodev,rw #{@new_resource.device} #{@new_resource.mount_point}") @provider.run_action(:remount) end end describe "enable_fs" do it "should enable mount if it is mounted and not enabled" do @new_resource.options("nodev,rw") stub_mounted_enabled(@provider, @mounted_output, "") filesystems = StringIO.new ::File.stub!(:open).with("/etc/filesystems", "a").and_yield(filesystems) @provider.run_action(:enable) filesystems.string.should match(%r{^/tmp/foo:\n\tdev\t\t= /dev/sdz1\n\tvfs\t\t= jfs2\n\tmount\t\t= false\n\toptions\t\t= nodev,rw\n$}) end it "should not enable mount if it is mounted and already enabled and mount options are unchanged" do stub_mounted_enabled(@provider, @mounted_output, @enabled_output) @new_resource.options "rw" @provider.should_not_receive(:enable_fs) @provider.run_action(:enable) end end describe "disable_fs" do it "should disable mount if it is mounted and enabled" do stub_mounted_enabled(@provider, @mounted_output, @enabled_output) ::File.stub!(:open).with("/etc/filesystems", "r").and_return(<<-ETCFILESYSTEMS) /tmp/foo: dev = /dev/sdz1 vfs = jfs2 log = /dev/hd8 mount = true check = true vol = /opt free = false quota = no /tmp/abc: dev = /dev/sdz2 vfs = jfs2 mount = true options = rw ETCFILESYSTEMS filesystems = StringIO.new ::File.stub!(:open).with("/etc/filesystems", "w").and_yield(filesystems) @provider.run_action(:disable) filesystems.string.should match(%r{^/tmp/abc:\s+dev\s+= /dev/sdz2\s+vfs\s+= jfs2\s+mount\s+= true\s+options\s+= rw\n$}) end it "should not disable mount if it is not mounted" do stub_mounted_enabled(@provider, @unmounted_output, "") @provider.should_not_receive(:disable_fs) @provider.run_action(:disable) end end end chef-11.8.2/spec/unit/provider/mount/mount_spec.rb0000644000004100000410000004330012254362222022146 0ustar www-datawww-data# # Author:: Joshua Timberman () # Copyright:: Copyright (c) 2008 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'ostruct' describe Chef::Provider::Mount::Mount do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Mount.new("/tmp/foo") @new_resource.device "/dev/sdz1" @new_resource.device_type :device @new_resource.fstype "ext3" @new_resource.supports :remount => false @provider = Chef::Provider::Mount::Mount.new(@new_resource, @run_context) ::File.stub!(:exists?).with("/dev/sdz1").and_return true ::File.stub!(:exists?).with("/tmp/foo").and_return true ::File.stub!(:realpath).with("/dev/sdz1").and_return "/dev/sdz1" ::File.stub!(:realpath).with("/tmp/foo").and_return "/tmp/foo" end describe "when discovering the current fs state" do before do @provider.stub!(:shell_out!).and_return(OpenStruct.new(:stdout => '')) ::File.stub!(:foreach).with("/etc/fstab") end it "should create a current resource with the same mount point and device" do @provider.load_current_resource @provider.current_resource.name.should == '/tmp/foo' @provider.current_resource.mount_point.should == '/tmp/foo' @provider.current_resource.device.should == '/dev/sdz1' end it "should accecpt device_type :uuid" do @new_resource.device_type :uuid @new_resource.device "d21afe51-a0fe-4dc6-9152-ac733763ae0a" @stdout_findfs = mock("STDOUT", :first => "/dev/sdz1") @provider.should_receive(:popen4).with("/sbin/findfs UUID=d21afe51-a0fe-4dc6-9152-ac733763ae0a").and_yield(@pid,@stdin,@stdout_findfs,@stderr).and_return(@status) @provider.load_current_resource() @provider.mountable? end describe "when dealing with network mounts" do { "nfs" => "nfsserver:/vol/path", "cifs" => "//cifsserver/share" }.each do |type, fs_spec| it "should detect network fs_spec (#{type})" do @new_resource.device fs_spec @provider.network_device?.should be_true end it "should ignore trailing slash and set mounted to true for network mount (#{type})" do @new_resource.device fs_spec @provider.stub!(:shell_out!).and_return(OpenStruct.new(:stdout => "#{fs_spec}/ on /tmp/foo type #{type} (rw)\n")) @provider.load_current_resource @provider.current_resource.mounted.should be_true end end end it "should raise an error if the mount device does not exist" do ::File.stub!(:exists?).with("/dev/sdz1").and_return false lambda { @provider.load_current_resource();@provider.mountable? }.should raise_error(Chef::Exceptions::Mount) end it "should not call mountable? with load_current_resource - CHEF-1565" do ::File.stub!(:exists?).with("/dev/sdz1").and_return false @provider.should_receive(:mounted?).and_return(true) @provider.should_receive(:enabled?).and_return(true) @provider.should_not_receive(:mountable?) @provider.load_current_resource end it "should raise an error if the mount device (uuid) does not exist" do @new_resource.device_type :uuid @new_resource.device "d21afe51-a0fe-4dc6-9152-ac733763ae0a" status_findfs = mock("Status", :exitstatus => 1) stdout_findfs = mock("STDOUT", :first => nil) @provider.should_receive(:popen4).with("/sbin/findfs UUID=d21afe51-a0fe-4dc6-9152-ac733763ae0a").and_yield(@pid,@stdin,stdout_findfs,@stderr).and_return(status_findfs) ::File.should_receive(:exists?).with("").and_return(false) lambda { @provider.load_current_resource();@provider.mountable? }.should raise_error(Chef::Exceptions::Mount) end it "should raise an error if the mount point does not exist" do ::File.stub!(:exists?).with("/tmp/foo").and_return false lambda { @provider.load_current_resource();@provider.mountable? }.should raise_error(Chef::Exceptions::Mount) end it "does not expect the device to exist for tmpfs" do @new_resource.fstype("tmpfs") @new_resource.device("whatever") lambda { @provider.load_current_resource();@provider.mountable? }.should_not raise_error end it "does not expect the device to exist for Fuse filesystems" do @new_resource.fstype("fuse") @new_resource.device("nilfs#xxx") lambda { @provider.load_current_resource();@provider.mountable? }.should_not raise_error end it "does not expect the device to exist if it's none" do @new_resource.device("none") lambda { @provider.load_current_resource();@provider.mountable? }.should_not raise_error end it "should set mounted true if the mount point is found in the mounts list" do @provider.stub!(:shell_out!).and_return(OpenStruct.new(:stdout => '/dev/sdz1 on /tmp/foo')) @provider.load_current_resource() @provider.current_resource.mounted.should be_true end it "should set mounted true if the symlink target of the device is found in the mounts list" do target = "/dev/mapper/target" ::File.stub!(:symlink?).with("#{@new_resource.device}").and_return(true) ::File.stub!(:readlink).with("#{@new_resource.device}").and_return(target) @provider.stub!(:shell_out!).and_return(OpenStruct.new(:stdout => "/dev/mapper/target on /tmp/foo type ext3 (rw)\n")) @provider.load_current_resource() @provider.current_resource.mounted.should be_true end it "should set mounted true if the mount point is found last in the mounts list" do mount = "/dev/sdy1 on #{@new_resource.mount_point} type ext3 (rw)\n" mount << "#{@new_resource.device} on #{@new_resource.mount_point} type ext3 (rw)\n" @provider.stub!(:shell_out!).and_return(OpenStruct.new(:stdout => mount)) @provider.load_current_resource() @provider.current_resource.mounted.should be_true end it "should set mounted false if the mount point is not last in the mounts list" do mount = "#{@new_resource.device} on #{@new_resource.mount_point} type ext3 (rw)\n" mount << "/dev/sdy1 on #{@new_resource.mount_point} type ext3 (rw)\n" @provider.stub!(:shell_out!).and_return(OpenStruct.new(:stdout => mount)) @provider.load_current_resource() @provider.current_resource.mounted.should be_false end it "mounted should be false if the mount point is not found in the mounts list" do @provider.stub!(:shell_out!).and_return(OpenStruct.new(:stdout => "/dev/sdy1 on /tmp/foo type ext3 (rw)\n")) @provider.load_current_resource() @provider.current_resource.mounted.should be_false end it "should set enabled to true if the mount point is last in fstab" do fstab1 = "/dev/sdy1 /tmp/foo ext3 defaults 1 2\n" fstab2 = "#{@new_resource.device} #{@new_resource.mount_point} ext3 defaults 1 2\n" ::File.stub!(:foreach).with("/etc/fstab").and_yield(fstab1).and_yield(fstab2) @provider.load_current_resource @provider.current_resource.enabled.should be_true end it "should set enabled to true if the mount point is not last in fstab and mount_point is a substring of another mount" do fstab1 = "#{@new_resource.device} #{@new_resource.mount_point} ext3 defaults 1 2\n" fstab2 = "/dev/sdy1 /tmp/foo/bar ext3 defaults 1 2\n" ::File.stub!(:foreach).with("/etc/fstab").and_yield(fstab1).and_yield(fstab2) @provider.load_current_resource @provider.current_resource.enabled.should be_true end it "should set enabled to true if the symlink target is in fstab" do target = "/dev/mapper/target" ::File.stub!(:symlink?).with("#{@new_resource.device}").and_return(true) ::File.stub!(:readlink).with("#{@new_resource.device}").and_return(target) fstab = "/dev/sdz1 /tmp/foo ext3 defaults 1 2\n" ::File.stub!(:foreach).with("/etc/fstab").and_yield fstab @provider.load_current_resource @provider.current_resource.enabled.should be_true end it "should set enabled to false if the mount point is not in fstab" do fstab = "/dev/sdy1 #{@new_resource.mount_point} ext3 defaults 1 2\n" ::File.stub!(:foreach).with("/etc/fstab").and_yield fstab @provider.load_current_resource @provider.current_resource.enabled.should be_false end it "should ignore commented lines in fstab " do fstab = "\# #{@new_resource.device} #{@new_resource.mount_point} ext3 defaults 1 2\n" ::File.stub!(:foreach).with("/etc/fstab").and_yield fstab @provider.load_current_resource @provider.current_resource.enabled.should be_false end it "should set enabled to false if the mount point is not last in fstab" do line_1 = "#{@new_resource.device} #{@new_resource.mount_point} ext3 defaults 1 2\n" line_2 = "/dev/sdy1 #{@new_resource.mount_point} ext3 defaults 1 2\n" ::File.stub!(:foreach).with("/etc/fstab").and_yield(line_1).and_yield(line_2) @provider.load_current_resource @provider.current_resource.enabled.should be_false end it "should not mangle the mount options if the device in fstab is a symlink" do target = "/dev/mapper/target" options = "rw,noexec,noauto" ::File.stub!(:symlink?).with(@new_resource.device).and_return(true) ::File.stub!(:readlink).with(@new_resource.device).and_return(target) fstab = "#{@new_resource.device} #{@new_resource.mount_point} #{@new_resource.fstype} #{options} 1 2\n" ::File.stub!(:foreach).with("/etc/fstab").and_yield fstab @provider.load_current_resource @provider.current_resource.options.should eq(options.split(',')) end it "should not mangle the mount options if the symlink target is in fstab" do target = "/dev/mapper/target" options = "rw,noexec,noauto" ::File.stub!(:symlink?).with(@new_resource.device).and_return(true) ::File.stub!(:readlink).with(@new_resource.device).and_return(target) fstab = "#{target} #{@new_resource.mount_point} #{@new_resource.fstype} #{options} 1 2\n" ::File.stub!(:foreach).with("/etc/fstab").and_yield fstab @provider.load_current_resource @provider.current_resource.options.should eq(options.split(',')) end end context "after the mount's state has been discovered" do before do @current_resource = Chef::Resource::Mount.new("/tmp/foo") @current_resource.device "/dev/sdz1" @current_resource.device_type :device @current_resource.fstype "ext3" @provider.current_resource = @current_resource end describe "mount_fs" do it "should mount the filesystem if it is not mounted" do @provider.rspec_reset @provider.should_receive(:shell_out!).with("mount -t ext3 -o defaults /dev/sdz1 /tmp/foo") @provider.mount_fs() end it "should mount the filesystem with options if options were passed" do options = "rw,noexec,noauto" @new_resource.options(%w{rw noexec noauto}) @provider.should_receive(:shell_out!).with("mount -t ext3 -o rw,noexec,noauto /dev/sdz1 /tmp/foo") @provider.mount_fs() end it "should mount the filesystem specified by uuid" do @new_resource.device "d21afe51-a0fe-4dc6-9152-ac733763ae0a" @new_resource.device_type :uuid @stdout_findfs = mock("STDOUT", :first => "/dev/sdz1") @provider.stub!(:popen4).with("/sbin/findfs UUID=d21afe51-a0fe-4dc6-9152-ac733763ae0a").and_yield(@pid,@stdin,@stdout_findfs,@stderr).and_return(@status) @stdout_mock = mock('stdout mock') @stdout_mock.stub!(:each).and_yield("#{@new_resource.device} on #{@new_resource.mount_point}") @provider.should_receive(:shell_out!).with("mount -t #{@new_resource.fstype} -o defaults -U #{@new_resource.device} #{@new_resource.mount_point}").and_return(@stdout_mock) @provider.mount_fs() end it "should not mount the filesystem if it is mounted" do @current_resource.stub!(:mounted).and_return(true) @provider.should_not_receive(:shell_out!) @provider.mount_fs() end end describe "umount_fs" do it "should umount the filesystem if it is mounted" do @current_resource.mounted(true) @provider.should_receive(:shell_out!).with("umount /tmp/foo") @provider.umount_fs() end it "should not umount the filesystem if it is not mounted" do @current_resource.mounted(false) @provider.should_not_receive(:shell_out!) @provider.umount_fs() end end describe "remount_fs" do it "should use mount -o remount if remount is supported" do @new_resource.supports({:remount => true}) @current_resource.mounted(true) @provider.should_receive(:shell_out!).with("mount -o remount #{@new_resource.mount_point}") @provider.remount_fs end it "should umount and mount if remount is not supported" do @new_resource.supports({:remount => false}) @current_resource.mounted(true) @provider.should_receive(:umount_fs) @provider.should_receive(:sleep).with(1) @provider.should_receive(:mount_fs) @provider.remount_fs() end it "should not try to remount at all if mounted is false" do @current_resource.mounted(false) @provider.should_not_receive(:shell_out!) @provider.should_not_receive(:umount_fs) @provider.should_not_receive(:mount_fs) @provider.remount_fs() end end describe "when enabling the fs" do it "should enable if enabled isn't true" do @current_resource.enabled(false) @fstab = StringIO.new ::File.stub!(:open).with("/etc/fstab", "a").and_yield(@fstab) @provider.enable_fs @fstab.string.should match(%r{^/dev/sdz1\s+/tmp/foo\s+ext3\s+defaults\s+0\s+2\s*$}) end it "should not enable if enabled is true and resources match" do @current_resource.enabled(true) @current_resource.fstype("ext3") @current_resource.options(["defaults"]) @current_resource.dump(0) @current_resource.pass(2) ::File.should_not_receive(:open).with("/etc/fstab", "a") @provider.enable_fs end it "should enable if enabled is true and resources do not match" do @current_resource.enabled(true) @current_resource.fstype("auto") @current_resource.options(["defaults"]) @current_resource.dump(0) @current_resource.pass(2) @fstab = StringIO.new ::File.stub(:readlines).and_return([]) ::File.should_receive(:open).once.with("/etc/fstab", "w").and_yield(@fstab) ::File.should_receive(:open).once.with("/etc/fstab", "a").and_yield(@fstab) @provider.enable_fs end end describe "when disabling the fs" do it "should disable if enabled is true" do @current_resource.enabled(true) other_mount = "/dev/sdy1 /tmp/foo ext3 defaults 1 2\n" this_mount = "/dev/sdz1 /tmp/foo ext3 defaults 1 2\n" @fstab_read = [this_mount, other_mount] ::File.stub!(:readlines).with("/etc/fstab").and_return(@fstab_read) @fstab_write = StringIO.new ::File.stub!(:open).with("/etc/fstab", "w").and_yield(@fstab_write) @provider.disable_fs @fstab_write.string.should match(Regexp.escape(other_mount)) @fstab_write.string.should_not match(Regexp.escape(this_mount)) end it "should disable if enabled is true and ignore commented lines" do @current_resource.enabled(true) fstab_read = [%q{/dev/sdy1 /tmp/foo ext3 defaults 1 2}, %q{/dev/sdz1 /tmp/foo ext3 defaults 1 2}, %q{#/dev/sdz1 /tmp/foo ext3 defaults 1 2}] fstab_write = StringIO.new ::File.stub!(:readlines).with("/etc/fstab").and_return(fstab_read) ::File.stub!(:open).with("/etc/fstab", "w").and_yield(fstab_write) @provider.disable_fs fstab_write.string.should match(%r{^/dev/sdy1 /tmp/foo ext3 defaults 1 2$}) fstab_write.string.should match(%r{^#/dev/sdz1 /tmp/foo ext3 defaults 1 2$}) fstab_write.string.should_not match(%r{^/dev/sdz1 /tmp/foo ext3 defaults 1 2$}) end it "should disable only the last entry if enabled is true" do @current_resource.stub!(:enabled).and_return(true) fstab_read = ["/dev/sdz1 /tmp/foo ext3 defaults 1 2\n", "/dev/sdy1 /tmp/foo ext3 defaults 1 2\n", "/dev/sdz1 /tmp/foo ext3 defaults 1 2\n"] fstab_write = StringIO.new ::File.stub!(:readlines).with("/etc/fstab").and_return(fstab_read) ::File.stub!(:open).with("/etc/fstab", "w").and_yield(fstab_write) @provider.disable_fs fstab_write.string.should == "/dev/sdz1 /tmp/foo ext3 defaults 1 2\n/dev/sdy1 /tmp/foo ext3 defaults 1 2\n" end it "should not disable if enabled is false" do @current_resource.stub!(:enabled).and_return(false) ::File.stub!(:readlines).with("/etc/fstab").and_return([]) ::File.should_not_receive(:open).and_yield(@fstab) @provider.disable_fs end end end end chef-11.8.2/spec/unit/provider/cookbook_file/0000755000004100000410000000000012254362222021110 5ustar www-datawww-datachef-11.8.2/spec/unit/provider/cookbook_file/content_spec.rb0000644000004100000410000000265312254362222024127 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::CookbookFile::Content do let(:new_resource) { mock('Chef::Resource::CookbookFile (new)', :cookbook_name => 'apache2', :cookbook => 'apache2') } let(:content) do @run_context = mock('Chef::RunContext') @current_resource = mock('Chef::Resource::CookbookFile (current)') Chef::Provider::CookbookFile::Content.new(new_resource, @current_resource, @run_context) end it "prefers the explicit cookbook name on the resource to the implicit one" do new_resource.stub!(:cookbook).and_return('nginx') content.send(:resource_cookbook).should == 'nginx' end it "falls back to the implicit cookbook name on the resource" do content.send(:resource_cookbook).should == 'apache2' end end chef-11.8.2/spec/unit/provider/erl_call_spec.rb0000644000004100000410000000531712254362222021425 0ustar www-datawww-data# # Author:: Joe Williams () # Copyright:: Copyright (c) 2009 Joe Williams # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::ErlCall do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::ErlCall.new("test", @node) @new_resource.code("io:format(\"burritos\", []).") @new_resource.node_name("chef@localhost") @new_resource.name("test") @provider = Chef::Provider::ErlCall.new(@new_resource, @run_context) @provider.stub!(:popen4).and_return(@status) @stdin = StringIO.new @stdout = StringIO.new('{ok, woohoo}') @stderr = StringIO.new @pid = 2342999 end it "should return a Chef::Provider::ErlCall object" do provider = Chef::Provider::ErlCall.new(@new_resource, @run_context) provider.should be_a_kind_of(Chef::Provider::ErlCall) end it "should return true" do @provider.load_current_resource.should eql(true) end describe "when running a distributed erl call resource" do before do @new_resource.cookie("nomnomnom") @new_resource.distributed(true) @new_resource.name_type("sname") end it "should write to stdin of the erl_call command" do expected_cmd = "erl_call -e -s -sname chef@localhost -c nomnomnom" @provider.should_receive(:popen4).with(expected_cmd, :waitlast => true).and_return([@pid, @stdin, @stdout, @stderr]) Process.should_receive(:wait).with(@pid) @provider.action_run @stdin.string.should == "#{@new_resource.code}\n" end end describe "when running a local erl call resource" do before do @new_resource.cookie(nil) @new_resource.distributed(false) @new_resource.name_type("name") end it "should write to stdin of the erl_call command" do @provider.should_receive(:popen4).with("erl_call -e -name chef@localhost ", :waitlast => true).and_return([@pid, @stdin, @stdout, @stderr]) Process.should_receive(:wait).with(@pid) @provider.action_run @stdin.string.should == "#{@new_resource.code}\n" end end end chef-11.8.2/spec/unit/provider/file_spec.rb0000644000004100000410000000331612254362222020564 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2008-2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'support/shared/unit/provider/file' describe Chef::Provider::File do let(:resource) do # need to check for/against mutating state within the new_resource, so don't mock resource = Chef::Resource::File.new("seattle") resource.path(resource_path) resource end let(:content) do content = mock('Chef::Provider::File::Content') end let(:node) { double('Chef::Node') } let(:events) { double('Chef::Events').as_null_object } # mock all the methods let(:run_context) { double('Chef::RunContext', :node => node, :events => events) } let(:enclosing_directory) { canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates"))) } let(:resource_path) { canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt"))) } # Subject let(:provider) do provider = described_class.new(resource, run_context) provider.stub!(:content).and_return(content) provider end it_behaves_like Chef::Provider::File end chef-11.8.2/spec/unit/provider/mdadm_spec.rb0000644000004100000410000001241312254362222020725 0ustar www-datawww-data# # Author:: Joe Williams () # Copyright:: Copyright (c) 2009 Joe Williams # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'ostruct' describe Chef::Provider::Mdadm do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Mdadm.new('/dev/md1') @new_resource.devices ["/dev/sdz1","/dev/sdz2","/dev/sdz3"] @provider = Chef::Provider::Mdadm.new(@new_resource, @run_context) end describe "when determining the current metadevice status" do it "should set the current resources mount point to the new resources mount point" do @provider.stub!(:shell_out!).and_return(OpenStruct.new(:status => 0)) @provider.load_current_resource @provider.current_resource.name.should == '/dev/md1' @provider.current_resource.raid_device.should == '/dev/md1' end it "determines that the metadevice exists when mdadm exit code is zero" do @provider.stub!(:shell_out!).with("mdadm --detail --test /dev/md1", :returns => [0,4]).and_return(OpenStruct.new(:status => 0)) @provider.load_current_resource @provider.current_resource.exists.should be_true end it "determines that the metadevice does not exist when mdadm exit code is 4" do @provider.stub!(:shell_out!).with("mdadm --detail --test /dev/md1", :returns => [0,4]).and_return(OpenStruct.new(:status => 4)) @provider.load_current_resource @provider.current_resource.exists.should be_false end end describe "after the metadevice status is known" do before(:each) do @current_resource = Chef::Resource::Mdadm.new('/dev/md1') @new_resource.level 5 @provider.stub!(:load_current_resource).and_return(true) @provider.current_resource = @current_resource end describe "when creating the metadevice" do it "should create the raid device if it doesnt exist" do @current_resource.exists(false) expected_command = "yes | mdadm --create /dev/md1 --level 5 --chunk=16 --metadata=0.90 --raid-devices 3 /dev/sdz1 /dev/sdz2 /dev/sdz3" @provider.should_receive(:shell_out!).with(expected_command) @provider.run_action(:create) end it "should specify a bitmap only if set" do @current_resource.exists(false) @new_resource.bitmap('grow') expected_command = "yes | mdadm --create /dev/md1 --level 5 --chunk=16 --metadata=0.90 --bitmap=grow --raid-devices 3 /dev/sdz1 /dev/sdz2 /dev/sdz3" @provider.should_receive(:shell_out!).with(expected_command) @provider.run_action(:create) @new_resource.should be_updated_by_last_action end it "should not specify a chunksize if raid level 1" do @current_resource.exists(false) @new_resource.level 1 expected_command = "yes | mdadm --create /dev/md1 --level 1 --metadata=0.90 --raid-devices 3 /dev/sdz1 /dev/sdz2 /dev/sdz3" @provider.should_receive(:shell_out!).with(expected_command) @provider.run_action(:create) @new_resource.should be_updated_by_last_action end it "should not create the raid device if it does exist" do @current_resource.exists(true) @provider.should_not_receive(:shell_out!) @provider.run_action(:create) @new_resource.should_not be_updated_by_last_action end end describe "when asembling the metadevice" do it "should assemble the raid device if it doesnt exist" do @current_resource.exists(false) expected_mdadm_cmd = "yes | mdadm --assemble /dev/md1 /dev/sdz1 /dev/sdz2 /dev/sdz3" @provider.should_receive(:shell_out!).with(expected_mdadm_cmd) @provider.run_action(:assemble) @new_resource.should be_updated_by_last_action end it "should not assemble the raid device if it doesnt exist" do @current_resource.exists(true) @provider.should_not_receive(:shell_out!) @provider.run_action(:assemble) @new_resource.should_not be_updated_by_last_action end end describe "when stopping the metadevice" do it "should stop the raid device if it exists" do @current_resource.exists(true) expected_mdadm_cmd = "yes | mdadm --stop /dev/md1" @provider.should_receive(:shell_out!).with(expected_mdadm_cmd) @provider.run_action(:stop) @new_resource.should be_updated_by_last_action end it "should not attempt to stop the raid device if it does not exist" do @current_resource.exists(false) @provider.should_not_receive(:shell_out!) @provider.run_action(:stop) @new_resource.should_not be_updated_by_last_action end end end end chef-11.8.2/spec/unit/provider/service/0000755000004100000410000000000012254362222017743 5ustar www-datawww-datachef-11.8.2/spec/unit/provider/service/debian_service_spec.rb0000644000004100000410000002722112254362222024250 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 HJK Solutions, LLC # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Service::Debian do before(:each) do @node = Chef::Node.new @node.automatic_attrs[:command] = {:ps => 'fuuuu'} @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Service.new("chef") @provider = Chef::Provider::Service::Debian.new(@new_resource, @run_context) @current_resource = Chef::Resource::Service.new("chef") @provider.current_resource = @current_resource @pid, @stdin, @stdout, @stderr = nil, nil, nil, nil end describe "load_current_resource" do it "ensures /usr/sbin/update-rc.d is available" do File.should_receive(:exists?).with("/usr/sbin/update-rc.d") .and_return(false) @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end context "when update-rc.d shows init linked to rc*.d/" do before do @provider.stub!(:assert_update_rcd_available) result = <<-UPDATE_RC_D_SUCCESS Removing any system startup links for /etc/init.d/chef ... /etc/rc0.d/K20chef /etc/rc1.d/K20chef /etc/rc2.d/S20chef /etc/rc3.d/S20chef /etc/rc4.d/S20chef /etc/rc5.d/S20chef /etc/rc6.d/K20chef UPDATE_RC_D_SUCCESS @stdout = StringIO.new(result) @stderr = StringIO.new @status = mock("Status", :exitstatus => 0, :stdout => @stdout) @provider.stub!(:shell_out!).and_return(@status) @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) end it "says the service is enabled" do @provider.service_currently_enabled?(@provider.get_priority).should be_true end it "stores the 'enabled' state" do Chef::Resource::Service.stub!(:new).and_return(@current_resource) @provider.load_current_resource.should equal(@current_resource) @current_resource.enabled.should be_true end end context "when update-rc.d shows init isn't linked to rc*.d/" do before do @provider.stub!(:assert_update_rcd_available) @status = mock("Status", :exitstatus => 0) @stdout = StringIO.new( " Removing any system startup links for /etc/init.d/chef ...") @stderr = StringIO.new @status = mock("Status", :exitstatus => 0, :stdout => @stdout) @provider.stub!(:shell_out!).and_return(@status) @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) end it "says the service is disabled" do @provider.service_currently_enabled?(@provider.get_priority).should be_false end it "stores the 'disabled' state" do Chef::Resource::Service.stub!(:new).and_return(@current_resource) @provider.load_current_resource.should equal(@current_resource) @current_resource.enabled.should be_false end end context "when update-rc.d fails" do before do @status = mock("Status", :exitstatus => -1) @provider.stub!(:popen4).and_return(@status) end it "raises an error" do @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end end {"Debian/Lenny and older" => { "linked" => { "stdout" => <<-STDOUT, Removing any system startup links for /etc/init.d/chef ... /etc/rc0.d/K20chef /etc/rc1.d/K20chef /etc/rc2.d/S20chef /etc/rc3.d/S20chef /etc/rc4.d/S20chef /etc/rc5.d/S20chef /etc/rc6.d/K20chef STDOUT "stderr" => "" }, "not linked" => { "stdout" => " Removing any system startup links for /etc/init.d/chef ...", "stderr" => "" }, }, "Debian/Squeeze and earlier" => { "linked" => { "stdout" => "update-rc.d: using dependency based boot sequencing", "stderr" => <<-STDERR, insserv: remove service /etc/init.d/../rc0.d/K20chef-client insserv: remove service /etc/init.d/../rc1.d/K20chef-client insserv: remove service /etc/init.d/../rc2.d/S20chef-client insserv: remove service /etc/init.d/../rc3.d/S20chef-client insserv: remove service /etc/init.d/../rc4.d/S20chef-client insserv: remove service /etc/init.d/../rc5.d/S20chef-client insserv: remove service /etc/init.d/../rc6.d/K20chef-client insserv: dryrun, not creating .depend.boot, .depend.start, and .depend.stop STDERR }, "not linked" => { "stdout" => "update-rc.d: using dependency based boot sequencing", "stderr" => "" } } }.each do |model, streams| context "on #{model}" do context "when update-rc.d shows init linked to rc*.d/" do before do @provider.stub!(:assert_update_rcd_available) @stdout = StringIO.new(streams["linked"]["stdout"]) @stderr = StringIO.new(streams["linked"]["stderr"]) @status = mock("Status", :exitstatus => 0, :stdout => @stdout) @provider.stub!(:shell_out!).and_return(@status) @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) end it "says the service is enabled" do @provider.service_currently_enabled?(@provider.get_priority).should be_true end it "stores the 'enabled' state" do Chef::Resource::Service.stub!(:new).and_return(@current_resource) @provider.load_current_resource.should equal(@current_resource) @current_resource.enabled.should be_true end it "stores the start/stop priorities of the service" do @provider.load_current_resource expected_priorities = {"6"=>[:stop, "20"], "0"=>[:stop, "20"], "1"=>[:stop, "20"], "2"=>[:start, "20"], "3"=>[:start, "20"], "4"=>[:start, "20"], "5"=>[:start, "20"]} @provider.current_resource.priority.should == expected_priorities end end context "when update-rc.d shows init isn't linked to rc*.d/" do before do @provider.stub!(:assert_update_rcd_available) @stdout = StringIO.new(streams["not linked"]["stdout"]) @stderr = StringIO.new(streams["not linked"]["stderr"]) @status = mock("Status", :exitstatus => 0, :stdout => @stdout) @provider.stub!(:shell_out!).and_return(@status) @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) end it "says the service is disabled" do @provider.service_currently_enabled?(@provider.get_priority).should be_false end it "stores the 'disabled' state" do Chef::Resource::Service.stub!(:new).and_return(@current_resource) @provider.load_current_resource.should equal(@current_resource) @current_resource.enabled.should be_false end end end end end describe "action_enable" do shared_examples_for "the service is up to date" do it "does not enable the service" do @provider.should_not_receive(:enable_service) @provider.action_enable @provider.set_updated_status @provider.new_resource.should_not be_updated end end shared_examples_for "the service is not up to date" do it "enables the service and sets the resource as updated" do @provider.should_receive(:enable_service).and_return(true) @provider.action_enable @provider.set_updated_status @provider.new_resource.should be_updated end end context "when the service is disabled" do before do @current_resource.enabled(false) end it_behaves_like "the service is not up to date" end context "when the service is enabled" do before do @current_resource.enabled(true) end context "and the service sets no priority" do it_behaves_like "the service is up to date" end context "and the service requests the same priority as is set" do before do @current_resource.priority(80) @new_resource.priority(80) end it_behaves_like "the service is up to date" end context "and the service requests a different priority than is set" do before do @current_resource.priority(20) @new_resource.priority(80) end it_behaves_like "the service is not up to date" end end end def expect_commands(provider, commands) commands.each do |command| provider.should_receive(:run_command).with({:command => command}) end end describe "enable_service" do let(:service_name) { @new_resource.service_name } context "when the service doesn't set a priority" do it "calls update-rc.d 'service_name' defaults" do expect_commands(@provider, [ "/usr/sbin/update-rc.d -f #{service_name} remove", "/usr/sbin/update-rc.d #{service_name} defaults" ]) @provider.enable_service end end context "when the service sets a simple priority" do before do @new_resource.priority(75) end it "calls update-rc.d 'service_name' defaults" do expect_commands(@provider, [ "/usr/sbin/update-rc.d -f #{service_name} remove", "/usr/sbin/update-rc.d #{service_name} defaults 75 25" ]) @provider.enable_service end end context "when the service sets complex priorities" do before do @new_resource.priority(2 => [:start, 20], 3 => [:stop, 55]) end it "calls update-rc.d 'service_name' with those priorities" do expect_commands(@provider, [ "/usr/sbin/update-rc.d -f #{service_name} remove", "/usr/sbin/update-rc.d #{service_name} start 20 2 . stop 55 3 . " ]) @provider.enable_service end end end describe "disable_service" do let(:service_name) { @new_resource.service_name } context "when the service doesn't set a priority" do it "calls update-rc.d -f 'service_name' remove + stop with default priority" do expect_commands(@provider, [ "/usr/sbin/update-rc.d -f #{service_name} remove", "/usr/sbin/update-rc.d -f #{service_name} stop 80 2 3 4 5 ." ]) @provider.disable_service end end context "when the service sets a simple priority" do before do @new_resource.priority(75) end it "calls update-rc.d -f 'service_name' remove + stop with the specified priority" do expect_commands(@provider, [ "/usr/sbin/update-rc.d -f #{service_name} remove", "/usr/sbin/update-rc.d -f #{service_name} stop #{100 - @new_resource.priority} 2 3 4 5 ." ]) @provider.disable_service end end end end chef-11.8.2/spec/unit/provider/service/freebsd_service_spec.rb0000644000004100000410000003743512254362222024450 0ustar www-datawww-data# # Author:: Bryan McLellan (btm@loftninjas.org) # Copyright:: Copyright (c) 2009 Bryan McLellan # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Service::Freebsd do before do @node = Chef::Node.new @node.automatic_attrs[:command] = {:ps => "ps -ax"} @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Service.new("apache22") @new_resource.pattern("httpd") @new_resource.supports({:status => false}) @current_resource = Chef::Resource::Service.new("apache22") @provider = Chef::Provider::Service::Freebsd.new(@new_resource,@run_context) @provider.action = :start @init_command = "/usr/local/etc/rc.d/apache22" Chef::Resource::Service.stub!(:new).and_return(@current_resource) end describe "load_current_resource" do before(:each) do @stdout = StringIO.new(<<-PS_SAMPLE) 413 ?? Ss 0:02.51 /usr/sbin/syslogd -s 539 ?? Is 0:00.14 /usr/sbin/sshd 545 ?? Ss 0:17.53 sendmail: accepting connections (sendmail) PS_SAMPLE @status = mock(:stdout => @stdout, :exitstatus => 0) @provider.stub!(:shell_out!).with(@node[:command][:ps]).and_return(@status) ::File.stub!(:exists?).and_return(false) ::File.stub!(:exists?).with("/usr/local/etc/rc.d/#{@new_resource.service_name}").and_return(true) @lines = mock("lines") @lines.stub!(:each).and_yield("sshd_enable=\"YES\""). and_yield("#{@new_resource.name}_enable=\"YES\"") ::File.stub!(:open).and_return(@lines) @rc_with_name = StringIO.new(<<-RC_SAMPLE) name="apache22" rcvar=`set_rcvar` RC_SAMPLE ::File.stub!(:open).with("/usr/local/etc/rc.d/#{@new_resource.service_name}").and_return(@rc_with_name) @provider.stub(:service_enable_variable_name).and_return nil end it "should create a current resource with the name of the new resource" do Chef::Resource::Service.should_receive(:new).and_return(@current_resource) @provider.load_current_resource end it "should set the current resources service name to the new resources service name" do @provider.load_current_resource @current_resource.service_name.should == @new_resource.service_name end it "should not raise an exception if the rcscript have a name variable" do @provider.load_current_resource lambda { @provider.service_enable_variable_name }.should_not raise_error(Chef::Exceptions::Service) end describe "when the service supports status" do before do @new_resource.supports({:status => true}) end it "should run '/etc/init.d/service_name status'" do @provider.should_receive(:shell_out).with("/usr/local/etc/rc.d/#{@current_resource.service_name} status").and_return(@status) @provider.load_current_resource end it "should set running to true if the status command returns 0" do @provider.should_receive(:shell_out).with("/usr/local/etc/rc.d/#{@current_resource.service_name} status").and_return(@status) @current_resource.should_receive(:running).with(true) @provider.load_current_resource end it "should set running to false if the status command returns anything except 0" do @provider.should_receive(:shell_out).with("/usr/local/etc/rc.d/#{@current_resource.service_name} status").and_raise(Mixlib::ShellOut::ShellCommandFailed) @current_resource.should_receive(:running).with(false) @provider.load_current_resource # @provider.current_resource.running.should be_false end end describe "when a status command has been specified" do before do @new_resource.status_command("/bin/chefhasmonkeypants status") end it "should run the services status command if one has been specified" do @provider.should_receive(:shell_out).with("/bin/chefhasmonkeypants status").and_return(@status) @provider.load_current_resource end end it "should raise error if the node has a nil ps attribute and no other means to get status" do @node.automatic_attrs[:command] = {:ps => nil} @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end it "should raise error if the node has an empty ps attribute and no other means to get status" do @node.automatic_attrs[:command] = {:ps => ""} @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end describe "when executing assertions" do it "should verify that /etc/rc.conf exists" do ::File.should_receive(:exists?).with("/etc/rc.conf") @provider.stub!(:service_enable_variable_name).and_return("#{@current_resource.service_name}_enable") @provider.load_current_resource end context "and the init script is not found" do [ "start", "reload", "restart", "enable" ].each do |action| it "should raise an exception when the action is #{action}" do ::File.stub!(:exists?).and_return(false) @provider.load_current_resource @provider.define_resource_requirements @provider.instance_variable_get("@rcd_script_found").should be_false @provider.action = action lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end end [ "stop", "disable" ].each do |action| it "should not raise an error when the action is #{action}" do @provider.action = action lambda { @provider.process_resource_requirements }.should_not raise_error end end end it "update state when current resource enabled state could not be determined" do ::File.should_receive(:exists?).with("/etc/rc.conf").and_return false @provider.load_current_resource @provider.instance_variable_get("@enabled_state_found").should be_false end it "update state when current resource enabled state could be determined" do ::File.stub!(:exist?).with("/usr/local/etc/rc.d/#{@new_resource.service_name}").and_return(true) ::File.should_receive(:exists?).with("/etc/rc.conf").and_return true @provider.load_current_resource @provider.instance_variable_get("@enabled_state_found").should be_false @provider.instance_variable_get("@rcd_script_found").should be_true @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service, "Could not find the service name in /usr/local/etc/rc.d/#{@current_resource.service_name} and rcvar") end it "should throw an exception if service line is missing from rc.d script" do pending "not implemented" do false.should be_true end end end describe "when we have a 'ps' attribute" do before do @node.automatic_attrs[:command] = {:ps => "ps -ax"} end it "should shell_out! the node's ps command" do @provider.should_receive(:shell_out!).with(@node[:command][:ps]).and_return(@status) @provider.load_current_resource end it "should read stdout of the ps command" do @provider.stub!(:shell_out!).and_return(@status) @stdout.should_receive(:each_line).and_return(true) @provider.load_current_resource end it "should set running to true if the regex matches the output" do @stdout.stub!(:each_line).and_yield("555 ?? Ss 0:05.16 /usr/sbin/cron -s"). and_yield(" 9881 ?? Ss 0:06.67 /usr/local/sbin/httpd -DNOHTTPACCEPT") @provider.load_current_resource @current_resource.running.should be_true end it "should set running to false if the regex doesn't match" do @provider.stub!(:shell_out!).and_return(@status) @provider.load_current_resource @current_resource.running.should be_false end it "should raise an exception if ps fails" do @provider.stub!(:shell_out!).and_raise(Mixlib::ShellOut::ShellCommandFailed) @provider.load_current_resource @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end end it "should return the current resource" do @provider.load_current_resource.should eql(@current_resource) end describe "when starting the service" do it "should call the start command if one is specified" do @new_resource.start_command("/etc/rc.d/chef startyousillysally") @provider.should_receive(:shell_out!).with("/etc/rc.d/chef startyousillysally") @provider.load_current_resource @provider.start_service() end it "should call '/usr/local/etc/rc.d/service_name faststart' if no start command is specified" do @provider.should_receive(:shell_out!).with("/usr/local/etc/rc.d/#{@new_resource.service_name} faststart") @provider.load_current_resource @provider.start_service() end end describe Chef::Provider::Service::Init, "stop_service" do it "should call the stop command if one is specified" do @new_resource.stop_command("/etc/init.d/chef itoldyoutostop") @provider.should_receive(:shell_out!).with("/etc/init.d/chef itoldyoutostop") @provider.load_current_resource @provider.stop_service() end it "should call '/usr/local/etc/rc.d/service_name faststop' if no stop command is specified" do @provider.should_receive(:shell_out!).with("/usr/local/etc/rc.d/#{@new_resource.service_name} faststop") @provider.load_current_resource @provider.stop_service() end end describe "when restarting a service" do it "should call 'restart' on the service_name if the resource supports it" do @new_resource.supports({:restart => true}) @provider.should_receive(:shell_out!).with("/usr/local/etc/rc.d/#{@new_resource.service_name} fastrestart") @provider.load_current_resource @provider.restart_service() end it "should call the restart_command if one has been specified" do @new_resource.restart_command("/etc/init.d/chef restartinafire") @provider.should_receive(:shell_out!).with("/etc/init.d/chef restartinafire") @provider.load_current_resource @provider.restart_service() end end describe "when the rcscript does not have a name variable" do before do @rc_without_name = StringIO.new(<<-RC_SAMPLE) rcvar=`set_rcvar` RC_SAMPLE ::File.stub!(:open).with("/usr/local/etc/rc.d/#{@current_resource.service_name}").and_return(@rc_with_noname) @provider.current_resource = @current_resource end describe "when rcvar returns foobar_enable" do before do @rcvar_stdout = < @rcvar_stdout, :exitstatus => 0) @provider.stub!(:shell_out!).with("/usr/local/etc/rc.d/#{@current_resource.service_name} rcvar").and_return(@status) end it "should get the service name from rcvar if the rcscript does not have a name variable" do @provider.load_current_resource @provider.unstub!(:service_enable_variable_name) @provider.service_enable_variable_name.should == "#{@current_resource.service_name}_enable" end it "should not raise an exception if the rcscript does not have a name variable" do @provider.load_current_resource lambda { @provider.service_enable_variable_name }.should_not raise_error(Chef::Exceptions::Service) end end describe "when rcvar does not return foobar_enable" do before do @rcvar_stdout = < @rcvar_stdout, :exitstatus => 0) @provider.stub!(:shell_out!).with("/usr/local/etc/rc.d/#{@current_resource.service_name} rcvar").and_return(@status) end [ "start", "reload", "restart", "enable" ].each do |action| it "should raise an exception when the action is #{action}" do @provider.action = action @provider.load_current_resource @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end end [ "stop", "disable" ].each do |action| it "should not raise an error when the action is #{action}" do ::File.stub!(:exist?).with("/usr/local/etc/rc.d/#{@new_resource.service_name}").and_return(true) @provider.action = action @provider.load_current_resource @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should_not raise_error(Chef::Exceptions::Service) end end end end end describe Chef::Provider::Service::Freebsd, "enable_service" do before do @provider.current_resource = @current_resource @provider.stub!(:service_enable_variable_name).and_return("#{@current_resource.service_name}_enable") end it "should enable the service if it is not enabled" do @current_resource.stub!(:enabled).and_return(false) @provider.should_receive(:read_rc_conf).and_return([ "foo", "#{@current_resource.service_name}_enable=\"NO\"", "bar" ]) @provider.should_receive(:write_rc_conf).with(["foo", "bar", "#{@current_resource.service_name}_enable=\"YES\""]) @provider.enable_service() end it "should enable the service if it is not enabled and not already specified in the rc.conf file" do @current_resource.stub!(:enabled).and_return(false) @provider.should_receive(:read_rc_conf).and_return([ "foo", "bar" ]) @provider.should_receive(:write_rc_conf).with(["foo", "bar", "#{@current_resource.service_name}_enable=\"YES\""]) @provider.enable_service() end it "should not enable the service if it is already enabled" do @current_resource.stub!(:enabled).and_return(true) @provider.should_not_receive(:write_rc_conf) @provider.enable_service end end describe Chef::Provider::Service::Freebsd, "disable_service" do before do @provider.current_resource = @current_resource @provider.stub!(:service_enable_variable_name).and_return("#{@current_resource.service_name}_enable") end it "should should disable the service if it is not disabled" do @current_resource.stub!(:enabled).and_return(true) @provider.should_receive(:read_rc_conf).and_return([ "foo", "#{@current_resource.service_name}_enable=\"YES\"", "bar" ]) @provider.should_receive(:write_rc_conf).with(["foo", "bar", "#{@current_resource.service_name}_enable=\"NO\""]) @provider.disable_service() end it "should not disable the service if it is already disabled" do @current_resource.stub!(:enabled).and_return(false) @provider.should_not_receive(:write_rc_conf) @provider.disable_service() end end end chef-11.8.2/spec/unit/provider/service/windows_spec.rb0000644000004100000410000002311712254362222023000 0ustar www-datawww-data# # Author:: Nuo Yan # Author:: Seth Chisamore # Copyright:: Copyright (c) 2010-2011 Opscode, Inc # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Service::Windows, "load_current_resource" do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Service.new("chef") @provider = Chef::Provider::Service::Windows.new(@new_resource, @run_context) Object.send(:remove_const, 'Win32') if defined?(Win32) Win32 = Module.new Win32::Service = Class.new Win32::Service::AUTO_START = 0x00000002 Win32::Service::DISABLED = 0x00000004 Win32::Service.stub!(:status).with(@new_resource.service_name).and_return( mock("StatusStruct", :current_state => "running")) Win32::Service.stub!(:config_info).with(@new_resource.service_name).and_return( mock("ConfigStruct", :start_type => "auto start")) Win32::Service.stub!(:exists?).and_return(true) end it "should set the current resources service name to the new resources service name" do @provider.load_current_resource @provider.current_resource.service_name.should == 'chef' end it "should return the current resource" do @provider.load_current_resource.should equal(@provider.current_resource) end it "should set the current resources status" do @provider.load_current_resource @provider.current_resource.running.should be_true end it "should set the current resources start type" do @provider.load_current_resource @provider.current_resource.enabled.should be_true end describe Chef::Provider::Service::Windows, "start_service" do before(:each) do Win32::Service.stub!(:status).with(@new_resource.service_name).and_return( mock("StatusStruct", :current_state => "stopped"), mock("StatusStruct", :current_state => "running")) end it "should call the start command if one is specified" do @new_resource.start_command "sc start chef" @provider.should_receive(:shell_out!).with("#{@new_resource.start_command}").and_return("Starting custom service") @provider.start_service @new_resource.updated_by_last_action?.should be_true end it "should use the built-in command if no start command is specified" do Win32::Service.should_receive(:start).with(@new_resource.service_name) @provider.start_service @new_resource.updated_by_last_action?.should be_true end it "should do nothing if the service does not exist" do Win32::Service.stub!(:exists?).with(@new_resource.service_name).and_return(false) Win32::Service.should_not_receive(:start).with(@new_resource.service_name) @provider.start_service @new_resource.updated_by_last_action?.should be_false end it "should do nothing if the service is running" do Win32::Service.stub!(:status).with(@new_resource.service_name).and_return( mock("StatusStruct", :current_state => "running")) @provider.load_current_resource Win32::Service.should_not_receive(:start).with(@new_resource.service_name) @provider.start_service @new_resource.updated_by_last_action?.should be_false end end describe Chef::Provider::Service::Windows, "stop_service" do before(:each) do Win32::Service.stub!(:status).with(@new_resource.service_name).and_return( mock("StatusStruct", :current_state => "running"), mock("StatusStruct", :current_state => "stopped")) end it "should call the stop command if one is specified" do @new_resource.stop_command "sc stop chef" @provider.should_receive(:shell_out!).with("#{@new_resource.stop_command}").and_return("Stopping custom service") @provider.stop_service @new_resource.updated_by_last_action?.should be_true end it "should use the built-in command if no stop command is specified" do Win32::Service.should_receive(:stop).with(@new_resource.service_name) @provider.stop_service @new_resource.updated_by_last_action?.should be_true end it "should do nothing if the service does not exist" do Win32::Service.stub!(:exists?).with(@new_resource.service_name).and_return(false) Win32::Service.should_not_receive(:stop).with(@new_resource.service_name) @provider.stop_service @new_resource.updated_by_last_action?.should be_false end it "should do nothing if the service is stopped" do Win32::Service.stub!(:status).with(@new_resource.service_name).and_return( mock("StatusStruct", :current_state => "stopped")) @provider.load_current_resource Win32::Service.should_not_receive(:stop).with(@new_resource.service_name) @provider.stop_service @new_resource.updated_by_last_action?.should be_false end end describe Chef::Provider::Service::Windows, "restart_service" do it "should call the restart command if one is specified" do @new_resource.restart_command "sc restart" @provider.should_receive(:shell_out!).with("#{@new_resource.restart_command}") @provider.restart_service @new_resource.updated_by_last_action?.should be_true end it "should stop then start the service if it is running" do Win32::Service.stub!(:status).with(@new_resource.service_name).and_return( mock("StatusStruct", :current_state => "running"), mock("StatusStruct", :current_state => "stopped"), mock("StatusStruct", :current_state => "stopped"), mock("StatusStruct", :current_state => "running")) Win32::Service.should_receive(:stop).with(@new_resource.service_name) Win32::Service.should_receive(:start).with(@new_resource.service_name) @provider.restart_service @new_resource.updated_by_last_action?.should be_true end it "should just start the service if it is stopped" do Win32::Service.stub!(:status).with(@new_resource.service_name).and_return( mock("StatusStruct", :current_state => "stopped"), mock("StatusStruct", :current_state => "stopped"), mock("StatusStruct", :current_state => "running")) Win32::Service.should_receive(:start).with(@new_resource.service_name) @provider.restart_service @new_resource.updated_by_last_action?.should be_true end it "should do nothing if the service does not exist" do Win32::Service.stub!(:exists?).with(@new_resource.service_name).and_return(false) Win32::Service.should_not_receive(:stop).with(@new_resource.service_name) Win32::Service.should_not_receive(:start).with(@new_resource.service_name) @provider.restart_service @new_resource.updated_by_last_action?.should be_false end end describe Chef::Provider::Service::Windows, "enable_service" do before(:each) do Win32::Service.stub!(:config_info).with(@new_resource.service_name).and_return( mock("ConfigStruct", :start_type => "disabled")) end it "should enable service" do Win32::Service.should_receive(:configure).with(:service_name => @new_resource.service_name, :start_type => Win32::Service::AUTO_START) @provider.enable_service @new_resource.updated_by_last_action?.should be_true end it "should do nothing if the service does not exist" do Win32::Service.stub!(:exists?).with(@new_resource.service_name).and_return(false) Win32::Service.should_not_receive(:configure) @provider.enable_service @new_resource.updated_by_last_action?.should be_false end it "should do nothing if the service is enabled" do Win32::Service.stub!(:config_info).with(@new_resource.service_name).and_return( mock("ConfigStruct", :start_type => "auto start")) Win32::Service.should_not_receive(:configure) @provider.enable_service @new_resource.updated_by_last_action?.should be_false end end describe Chef::Provider::Service::Windows, "disable_service" do before(:each) do Win32::Service.stub!(:config_info).with(@new_resource.service_name).and_return( mock("ConfigStruct", :start_type => "auto start")) end it "should disable service" do Win32::Service.should_receive(:configure).with(:service_name => @new_resource.service_name, :start_type => Win32::Service::DISABLED) @provider.disable_service @new_resource.updated_by_last_action?.should be_true end it "should do nothing if the service does not exist" do Win32::Service.stub!(:exists?).with(@new_resource.service_name).and_return(false) Win32::Service.should_not_receive(:configure) @provider.disable_service @new_resource.updated_by_last_action?.should be_false end it "should do nothing if the service is disabled" do Win32::Service.stub!(:config_info).with(@new_resource.service_name).and_return( mock("ConfigStruct", :start_type => "disabled")) @provider.load_current_resource Win32::Service.should_not_receive(:configure) @provider.disable_service @new_resource.updated_by_last_action?.should be_false end end end chef-11.8.2/spec/unit/provider/service/gentoo_service_spec.rb0000644000004100000410000001247112254362222024322 0ustar www-datawww-data# # Author:: Lee Jensen () # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Service::Gentoo do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Service.new("chef") @current_resource = Chef::Resource::Service.new("chef") @provider = Chef::Provider::Service::Gentoo.new(@new_resource, @run_context) Chef::Resource::Service.stub!(:new).and_return(@current_resource) @status = mock("Status", :exitstatus => 0, :stdout => @stdout) @provider.stub!(:shell_out).and_return(@status) File.stub!(:exists?).with("/etc/init.d/chef").and_return(true) File.stub!(:exists?).with("/sbin/rc-update").and_return(true) File.stub!(:exists?).with("/etc/runlevels/default/chef").and_return(false) File.stub!(:readable?).with("/etc/runlevels/default/chef").and_return(false) end # new test: found_enabled state # describe "load_current_resource" do it "should raise Chef::Exceptions::Service if /sbin/rc-update does not exist" do File.should_receive(:exists?).with("/sbin/rc-update").and_return(false) @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end it "should track when service file is not found in /etc/runlevels" do @provider.load_current_resource @provider.instance_variable_get("@found_script").should be_false end it "should track when service file is found in /etc/runlevels/**/" do Dir.stub!(:glob).with("/etc/runlevels/**/chef").and_return(["/etc/runlevels/default/chef"]) @provider.load_current_resource @provider.instance_variable_get("@found_script").should be_true end describe "when detecting the service enable state" do describe "and the glob returns a default service script file" do before do Dir.stub!(:glob).with("/etc/runlevels/**/chef").and_return(["/etc/runlevels/default/chef"]) end describe "and the file exists and is readable" do before do File.stub!(:exists?).with("/etc/runlevels/default/chef").and_return(true) File.stub!(:readable?).with("/etc/runlevels/default/chef").and_return(true) end it "should set enabled to true" do @provider.load_current_resource @current_resource.enabled.should be_true end end describe "and the file exists but is not readable" do before do File.stub!(:exists?).with("/etc/runlevels/default/chef").and_return(true) File.stub!(:readable?).with("/etc/runlevels/default/chef").and_return(false) end it "should set enabled to false" do @provider.load_current_resource @current_resource.enabled.should be_false end end describe "and the file does not exist" do before do File.stub!(:exists?).with("/etc/runlevels/default/chef").and_return(false) File.stub!(:readable?).with("/etc/runlevels/default/chef").and_return("foobarbaz") end it "should set enabled to false" do @provider.load_current_resource @current_resource.enabled.should be_false end end end end it "should return the current_resource" do @provider.load_current_resource.should == @current_resource end it "should support the status command automatically" do @provider.load_current_resource @new_resource.supports[:status].should be_true end it "should support the restart command automatically" do @provider.load_current_resource @new_resource.supports[:restart].should be_true end it "should not support the reload command automatically" do @provider.load_current_resource @new_resource.supports[:reload].should_not be_true end end describe "action_methods" do before(:each) { @provider.stub!(:load_current_resource).and_return(@current_resource) } describe Chef::Provider::Service::Gentoo, "enable_service" do it "should call rc-update add *service* default" do @provider.should_receive(:run_command).with({:command => "/sbin/rc-update add chef default"}) @provider.enable_service() end end describe Chef::Provider::Service::Gentoo, "disable_service" do it "should call rc-update del *service* default" do @provider.should_receive(:run_command).with({:command => "/sbin/rc-update del chef default"}) @provider.disable_service() end end end end chef-11.8.2/spec/unit/provider/service/arch_service_spec.rb0000644000004100000410000003137112254362222023744 0ustar www-datawww-data# # Author:: Jan Zimmek () # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'ostruct' # most of this code has been ripped from init_service_spec.rb # and is only slightly modified to match "arch" needs. describe Chef::Provider::Service::Arch, "load_current_resource" do before(:each) do @node = Chef::Node.new @node.automatic_attrs[:command] = {:ps => "ps -ef"} @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Service.new("chef") @new_resource.pattern("chef") @new_resource.supports({:status => false}) @provider = Chef::Provider::Service::Arch.new(@new_resource, @run_context) ::File.stub!(:exists?).with("/etc/rc.conf").and_return(true) ::File.stub!(:read).with("/etc/rc.conf").and_return("DAEMONS=(network apache sshd)") end describe "when first created" do it "should set the current resources service name to the new resources service name" do @provider.stub(:shell_out).and_return(OpenStruct.new(:exitstatus => 0, :stdout => "")) @provider.load_current_resource @provider.current_resource.service_name.should == 'chef' end end describe "when the service supports status" do before do @new_resource.supports({:status => true}) end it "should run '/etc/rc.d/service_name status'" do @provider.should_receive(:shell_out).with("/etc/rc.d/chef status").and_return(OpenStruct.new(:exitstatus => 0)) @provider.load_current_resource end it "should set running to true if the status command returns 0" do @provider.stub!(:shell_out).with("/etc/rc.d/chef status").and_return(OpenStruct.new(:exitstatus => 0)) @provider.load_current_resource @provider.current_resource.running.should be_true end it "should set running to false if the status command returns anything except 0" do @provider.stub!(:shell_out).with("/etc/rc.d/chef status").and_return(OpenStruct.new(:exitstatus => 1)) @provider.load_current_resource @provider.current_resource.running.should be_false end it "should set running to false if the status command raises" do @provider.stub!(:shell_out).with("/etc/rc.d/chef status").and_raise(Mixlib::ShellOut::ShellCommandFailed) @provider.load_current_resource @provider.current_resource.running.should be_false end end describe "when a status command has been specified" do before do @new_resource.status_command("/etc/rc.d/chefhasmonkeypants status") end it "should run the services status command if one has been specified" do @provider.should_receive(:shell_out).with("/etc/rc.d/chefhasmonkeypants status").and_return(OpenStruct.new(:exitstatus => 0)) @provider.load_current_resource end end it "should raise error if the node has a nil ps attribute and no other means to get status" do @node.automatic_attrs[:command] = {:ps => nil} @provider.define_resource_requirements @provider.action = :start lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end it "should raise error if the node has an empty ps attribute and no other means to get status" do @node.automatic_attrs[:command] = {:ps => ""} @provider.define_resource_requirements @provider.action = :start lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end it "should fail if file /etc/rc.conf does not exist" do ::File.stub!(:exists?).with("/etc/rc.conf").and_return(false) lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Service) end it "should fail if file /etc/rc.conf does not contain DAEMONS array" do ::File.stub!(:read).with("/etc/rc.conf").and_return("") lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Service) end describe "when discovering service status with ps" do before do @stdout = StringIO.new(<<-DEFAULT_PS) aj 7842 5057 0 21:26 pts/2 00:00:06 vi init.rb aj 7903 5016 0 21:26 pts/5 00:00:00 /bin/bash aj 8119 6041 0 21:34 pts/3 00:00:03 vi init_service_spec.rb DEFAULT_PS @status = mock("Status", :exitstatus => 0, :stdout => @stdout) @provider.stub!(:shell_out!).and_return(@status) @node.automatic_attrs[:command] = {:ps => "ps -ef"} end it "determines the service is running when it appears in ps" do @stdout = StringIO.new(<<-RUNNING_PS) aj 7842 5057 0 21:26 pts/2 00:00:06 chef aj 7842 5057 0 21:26 pts/2 00:00:06 poos RUNNING_PS @status.stub!(:stdout).and_return(@stdout) @provider.load_current_resource @provider.current_resource.running.should be_true end it "determines the service is not running when it does not appear in ps" do @provider.stub!(:shell_out!).and_return(@status) @provider.load_current_resource @provider.current_resource.running.should be_false end it "should raise an exception if ps fails" do @provider.stub!(:shell_out!).and_raise(Mixlib::ShellOut::ShellCommandFailed) @provider.load_current_resource @provider.action = :start @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end end it "should return existing entries in DAEMONS array" do ::File.stub!(:read).with("/etc/rc.conf").and_return("DAEMONS=(network !apache ssh)") @provider.daemons.should == ['network', '!apache', 'ssh'] end context "when the current service status is known" do before do @current_resource = Chef::Resource::Service.new("chef") @provider.current_resource = @current_resource end describe Chef::Provider::Service::Arch, "enable_service" do # before(:each) do # @new_resource = mock("Chef::Resource::Service", # :null_object => true, # :name => "chef", # :service_name => "chef", # :running => false # ) # @new_resource.stub!(:start_command).and_return(false) # # @provider = Chef::Provider::Service::Arch.new(@node, @new_resource) # Chef::Resource::Service.stub!(:new).and_return(@current_resource) # end it "should add chef to DAEMONS array" do ::File.stub!(:read).with("/etc/rc.conf").and_return("DAEMONS=(network)") @provider.should_receive(:update_daemons).with(['network', 'chef']) @provider.enable_service() end end describe Chef::Provider::Service::Arch, "disable_service" do # before(:each) do # @new_resource = mock("Chef::Resource::Service", # :null_object => true, # :name => "chef", # :service_name => "chef", # :running => false # ) # @new_resource.stub!(:start_command).and_return(false) # # @provider = Chef::Provider::Service::Arch.new(@node, @new_resource) # Chef::Resource::Service.stub!(:new).and_return(@current_resource) # end it "should remove chef from DAEMONS array" do ::File.stub!(:read).with("/etc/rc.conf").and_return("DAEMONS=(network chef)") @provider.should_receive(:update_daemons).with(['network', '!chef']) @provider.disable_service() end end describe Chef::Provider::Service::Arch, "start_service" do # before(:each) do # @new_resource = mock("Chef::Resource::Service", # :null_object => true, # :name => "chef", # :service_name => "chef", # :running => false # ) # @new_resource.stub!(:start_command).and_return(false) # # @provider = Chef::Provider::Service::Arch.new(@node, @new_resource) # Chef::Resource::Service.stub!(:new).and_return(@current_resource) # end it "should call the start command if one is specified" do @new_resource.stub!(:start_command).and_return("/etc/rc.d/chef startyousillysally") @provider.should_receive(:shell_out!).with("/etc/rc.d/chef startyousillysally") @provider.start_service() end it "should call '/etc/rc.d/service_name start' if no start command is specified" do @provider.should_receive(:shell_out!).with("/etc/rc.d/#{@new_resource.service_name} start") @provider.start_service() end end describe Chef::Provider::Service::Arch, "stop_service" do # before(:each) do # @new_resource = mock("Chef::Resource::Service", # :null_object => true, # :name => "chef", # :service_name => "chef", # :running => false # ) # @new_resource.stub!(:stop_command).and_return(false) # # @provider = Chef::Provider::Service::Arch.new(@node, @new_resource) # Chef::Resource::Service.stub!(:new).and_return(@current_resource) # end it "should call the stop command if one is specified" do @new_resource.stub!(:stop_command).and_return("/etc/rc.d/chef itoldyoutostop") @provider.should_receive(:shell_out!).with("/etc/rc.d/chef itoldyoutostop") @provider.stop_service() end it "should call '/etc/rc.d/service_name stop' if no stop command is specified" do @provider.should_receive(:shell_out!).with("/etc/rc.d/#{@new_resource.service_name} stop") @provider.stop_service() end end describe Chef::Provider::Service::Arch, "restart_service" do # before(:each) do # @new_resource = mock("Chef::Resource::Service", # :null_object => true, # :name => "chef", # :service_name => "chef", # :running => false # ) # @new_resource.stub!(:restart_command).and_return(false) # @new_resource.stub!(:supports).and_return({:restart => false}) # # @provider = Chef::Provider::Service::Arch.new(@node, @new_resource) # Chef::Resource::Service.stub!(:new).and_return(@current_resource) # end it "should call 'restart' on the service_name if the resource supports it" do @new_resource.stub!(:supports).and_return({:restart => true}) @provider.should_receive(:shell_out!).with("/etc/rc.d/#{@new_resource.service_name} restart") @provider.restart_service() end it "should call the restart_command if one has been specified" do @new_resource.stub!(:restart_command).and_return("/etc/rc.d/chef restartinafire") @provider.should_receive(:shell_out!).with("/etc/rc.d/#{@new_resource.service_name} restartinafire") @provider.restart_service() end it "should just call stop, then start when the resource doesn't support restart and no restart_command is specified" do @provider.should_receive(:stop_service) @provider.should_receive(:sleep).with(1) @provider.should_receive(:start_service) @provider.restart_service() end end describe Chef::Provider::Service::Arch, "reload_service" do # before(:each) do # @new_resource = mock("Chef::Resource::Service", # :null_object => true, # :name => "chef", # :service_name => "chef", # :running => false # ) # @new_resource.stub!(:reload_command).and_return(false) # @new_resource.stub!(:supports).and_return({:reload => false}) # # @provider = Chef::Provider::Service::Arch.new(@node, @new_resource) # Chef::Resource::Service.stub!(:new).and_return(@current_resource) # end it "should call 'reload' on the service if it supports it" do @new_resource.stub!(:supports).and_return({:reload => true}) @provider.should_receive(:shell_out!).with("/etc/rc.d/#{@new_resource.service_name} reload") @provider.reload_service() end it "should should run the user specified reload command if one is specified and the service doesn't support reload" do @new_resource.stub!(:reload_command).and_return("/etc/rc.d/chef lollerpants") @provider.should_receive(:shell_out!).with("/etc/rc.d/#{@new_resource.service_name} lollerpants") @provider.reload_service() end end end end chef-11.8.2/spec/unit/provider/service/upstart_service_spec.rb0000644000004100000410000003215212254362222024527 0ustar www-datawww-data# # Author:: Bryan McLellan (btm@loftninjas.org) # Copyright:: Copyright (c) 2010 Bryan McLellan # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Service::Upstart do before(:each) do @node =Chef::Node.new @node.name('upstarter') @node.automatic_attrs[:platform] = 'ubuntu' @node.automatic_attrs[:platform_version] = '9.10' @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Service.new("rsyslog") @provider = Chef::Provider::Service::Upstart.new(@new_resource, @run_context) end describe "when first created" do before do @platform = nil end it "should return /etc/event.d as the upstart job directory when running on Ubuntu 9.04" do @node.automatic_attrs[:platform_version] = '9.04' #Chef::Platform.stub!(:find_platform_and_version).and_return([ "ubuntu", "9.04" ]) @provider = Chef::Provider::Service::Upstart.new(@new_resource, @run_context) @provider.instance_variable_get(:@upstart_job_dir).should == "/etc/event.d" @provider.instance_variable_get(:@upstart_conf_suffix).should == "" end it "should return /etc/init as the upstart job directory when running on Ubuntu 9.10" do @node.automatic_attrs[:platform_version] = '9.10' @provider = Chef::Provider::Service::Upstart.new(@new_resource, @run_context) @provider.instance_variable_get(:@upstart_job_dir).should == "/etc/init" @provider.instance_variable_get(:@upstart_conf_suffix).should == ".conf" end it "should return /etc/init as the upstart job directory by default" do @node.automatic_attrs[:platform_version] = '9000' @provider = Chef::Provider::Service::Upstart.new(@new_resource, @run_context) @provider.instance_variable_get(:@upstart_job_dir).should == "/etc/init" @provider.instance_variable_get(:@upstart_conf_suffix).should == ".conf" end end describe "load_current_resource" do before(:each) do @node.automatic_attrs[:command] = {:ps => "ps -ax"} @current_resource = Chef::Resource::Service.new("rsyslog") Chef::Resource::Service.stub!(:new).and_return(@current_resource) @status = mock("Status", :exitstatus => 0) @provider.stub!(:popen4).and_return(@status) @stdin = StringIO.new @stdout = StringIO.new @stderr = StringIO.new @pid = mock("PID") ::File.stub!(:exists?).and_return(true) ::File.stub!(:open).and_return(true) end it "should create a current resource with the name of the new resource" do Chef::Resource::Service.should_receive(:new).and_return(@current_resource) @provider.load_current_resource end it "should set the current resources service name to the new resources service name" do @current_resource.should_receive(:service_name).with(@new_resource.service_name) @provider.load_current_resource end it "should run '/sbin/status rsyslog'" do @provider.should_receive(:popen4).with("/sbin/status rsyslog").and_return(@status) @provider.load_current_resource end describe "when the status command uses the new format" do before do end it "should set running to true if the status command returns 0" do @stdout = StringIO.new("rsyslog start/running") @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.load_current_resource @current_resource.running.should be_true end it "should set running to false if the status command returns anything except 0" do @stdout = StringIO.new("rsyslog stop/waiting") @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.load_current_resource @current_resource.running.should be_false end end describe "when the status command uses the old format" do it "should set running to true if the status command returns 0" do @stdout = StringIO.new("rsyslog (start) running, process 32225") @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.load_current_resource @current_resource.running.should be_true end it "should set running to false if the status command returns anything except 0" do @stdout = StringIO.new("rsyslog (stop) waiting") @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.load_current_resource @current_resource.running.should be_false end end it "should set running to false if it catches a Chef::Exceptions::Exec" do @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_raise(Chef::Exceptions::Exec) @current_resource.should_receive(:running).with(false) @provider.load_current_resource end it "should set enabled to true when it finds 'starts on'" do @lines = mock("start on filesystem", :gets => "start on filesystem") ::File.stub!(:open).and_yield(@lines) @current_resource.should_receive(:running).with(false) @provider.load_current_resource end it "should set enabled to false when it finds '#starts on'" do @lines = mock("start on filesystem", :gets => "#start on filesystem") ::File.stub!(:open).and_yield(@lines) @current_resource.should_receive(:running).with(false) @provider.load_current_resource end it "should assume disable when no job configuration file is found" do ::File.stub!(:exists?).and_return(false) @current_resource.should_receive(:running).with(false) @provider.load_current_resource end it "should track state when the upstart configuration file fails to load" do File.should_receive(:exists?).and_return false @provider.load_current_resource @provider.instance_variable_get("@config_file_found").should == false end describe "when a status command has been specified" do before do @new_resource.stub!(:status_command).and_return("/bin/chefhasmonkeypants status") end it "should run the services status command if one has been specified" do @provider.stub!(:run_command_with_systems_locale).with({:command => "/bin/chefhasmonkeypants status"}).and_return(0) @current_resource.should_receive(:running).with(true) @provider.load_current_resource end it "should track state when the user-provided status command fails" do @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_raise(Chef::Exceptions::Exec) @provider.load_current_resource @provider.instance_variable_get("@command_success").should == false end it "should set running to false if it catches a Chef::Exceptions::Exec when using a status command" do @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_raise(Chef::Exceptions::Exec) @current_resource.should_receive(:running).with(false) @provider.load_current_resource end end it "should track state when we fail to obtain service status via upstart_state" do @provider.should_receive(:upstart_state).and_raise Chef::Exceptions::Exec @provider.load_current_resource @provider.instance_variable_get("@command_success").should == false end it "should return the current resource" do @provider.load_current_resource.should eql(@current_resource) end end describe "enable and disable service" do before(:each) do @current_resource = Chef::Resource::Service.new('rsyslog') Chef::Resource::Service.stub!(:new).and_return(@current_resource) @provider.current_resource = @current_resource Chef::Util::FileEdit.stub!(:new) end it "should enable the service if it is not enabled" do @file = Object.new Chef::Util::FileEdit.stub!(:new).and_return(@file) @current_resource.stub!(:enabled).and_return(false) @file.should_receive(:search_file_replace) @file.should_receive(:write_file) @provider.enable_service() end it "should disable the service if it is enabled" do @file = Object.new Chef::Util::FileEdit.stub!(:new).and_return(@file) @current_resource.stub!(:enabled).and_return(true) @file.should_receive(:search_file_replace) @file.should_receive(:write_file) @provider.disable_service() end end describe "start and stop service" do before(:each) do @current_resource = Chef::Resource::Service.new('rsyslog') Chef::Resource::Service.stub!(:new).and_return(@current_resource) @provider.current_resource = @current_resource end it "should call the start command if one is specified" do @new_resource.stub!(:start_command).and_return("/sbin/rsyslog startyousillysally") @provider.should_receive(:shell_out!).with("/sbin/rsyslog startyousillysally") @provider.start_service() end it "should call '/sbin/start service_name' if no start command is specified" do @provider.should_receive(:run_command_with_systems_locale).with({:command => "/sbin/start #{@new_resource.service_name}"}).and_return(0) @provider.start_service() end it "should not call '/sbin/start service_name' if it is already running" do @current_resource.stub!(:running).and_return(true) @provider.should_not_receive(:run_command_with_systems_locale).with({:command => "/sbin/start #{@new_resource.service_name}"}) @provider.start_service() end it "should pass parameters to the start command if they are provided" do @new_resource = Chef::Resource::Service.new("rsyslog") @new_resource.parameters({ "OSD_ID" => "2" }) @provider = Chef::Provider::Service::Upstart.new(@new_resource, @run_context) @provider.current_resource = @current_resource @provider.should_receive(:run_command_with_systems_locale).with({:command => "/sbin/start rsyslog OSD_ID=2"}).and_return(0) @provider.start_service() end it "should call the restart command if one is specified" do @current_resource.stub!(:running).and_return(true) @new_resource.stub!(:restart_command).and_return("/sbin/rsyslog restartyousillysally") @provider.should_receive(:shell_out!).with("/sbin/rsyslog restartyousillysally") @provider.restart_service() end it "should call '/sbin/restart service_name' if no restart command is specified" do @current_resource.stub!(:running).and_return(true) @provider.should_receive(:run_command_with_systems_locale).with({:command => "/sbin/restart #{@new_resource.service_name}"}).and_return(0) @provider.restart_service() end it "should call '/sbin/start service_name' if restart_service is called for a stopped service" do @current_resource.stub!(:running).and_return(false) @provider.should_receive(:run_command_with_systems_locale).with({:command => "/sbin/start #{@new_resource.service_name}"}).and_return(0) @provider.restart_service() end it "should call the reload command if one is specified" do @current_resource.stub!(:running).and_return(true) @new_resource.stub!(:reload_command).and_return("/sbin/rsyslog reloadyousillysally") @provider.should_receive(:shell_out!).with("/sbin/rsyslog reloadyousillysally") @provider.reload_service() end it "should call '/sbin/reload service_name' if no reload command is specified" do @current_resource.stub!(:running).and_return(true) @provider.should_receive(:run_command_with_systems_locale).with({:command => "/sbin/reload #{@new_resource.service_name}"}).and_return(0) @provider.reload_service() end it "should call the stop command if one is specified" do @current_resource.stub!(:running).and_return(true) @new_resource.stub!(:stop_command).and_return("/sbin/rsyslog stopyousillysally") @provider.should_receive(:shell_out!).with("/sbin/rsyslog stopyousillysally") @provider.stop_service() end it "should call '/sbin/stop service_name' if no stop command is specified" do @current_resource.stub!(:running).and_return(true) @provider.should_receive(:run_command_with_systems_locale).with({:command => "/sbin/stop #{@new_resource.service_name}"}).and_return(0) @provider.stop_service() end it "should not call '/sbin/stop service_name' if it is already stopped" do @current_resource.stub!(:running).and_return(false) @provider.should_not_receive(:run_command_with_systems_locale).with({:command => "/sbin/stop #{@new_resource.service_name}"}) @provider.stop_service() end end end chef-11.8.2/spec/unit/provider/service/insserv_service_spec.rb0000644000004100000410000000526012254362222024516 0ustar www-datawww-data# # Author:: Bryan McLellan # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Service::Insserv do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @node.automatic_attrs[:command] = {:ps => "ps -ax"} @new_resource = Chef::Resource::Service.new("initgrediant") @current_resource = Chef::Resource::Service.new("initgrediant") @provider = Chef::Provider::Service::Insserv.new(@new_resource, @run_context) @status = mock("Process::Status mock", :exitstatus => 0, :stdout => "") @provider.stub!(:shell_out!).and_return(@status) end describe "load_current_resource" do describe "when startup links exist" do before do Dir.stub!(:glob).with("/etc/rc**/S*initgrediant").and_return(["/etc/rc5.d/S18initgrediant", "/etc/rc2.d/S18initgrediant", "/etc/rc4.d/S18initgrediant", "/etc/rc3.d/S18initgrediant"]) end it "sets the current enabled status to true" do @provider.load_current_resource @provider.current_resource.enabled.should be_true end end describe "when startup links do not exist" do before do Dir.stub!(:glob).with("/etc/rc**/S*initgrediant").and_return([]) end it "sets the current enabled status to false" do @provider.load_current_resource @provider.current_resource.enabled.should be_false end end end describe "enable_service" do it "should call insserv and create the default links" do @provider.should_receive(:run_command).with({:command=>"/sbin/insserv -r -f #{@new_resource.service_name}"}) @provider.should_receive(:run_command).with({:command=>"/sbin/insserv -d -f #{@new_resource.service_name}"}) @provider.enable_service end end describe "disable_service" do it "should call insserv and remove the links" do @provider.should_receive(:run_command).with({:command=>"/sbin/insserv -r -f #{@new_resource.service_name}"}) @provider.disable_service end end end chef-11.8.2/spec/unit/provider/service/solaris_smf_service_spec.rb0000644000004100000410000001221112254362222025340 0ustar www-datawww-data# # Author:: Toomas Pelberg () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Service::Solaris do before(:each) do @node =Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Service.new('chef') @current_resource = Chef::Resource::Service.new('chef') @provider = Chef::Provider::Service::Solaris.new(@new_resource, @run_context) Chef::Resource::Service.stub!(:new).and_return(@current_resource) @stdin = StringIO.new @stdout = StringIO.new @stderr = StringIO.new @pid = 2342 @stdout_string = "state disabled" @stdout.stub!(:gets).and_return(@stdout_string) @status = mock("Status", :exitstatus => 0, :stdout => @stdout) @provider.stub!(:shell_out!).and_return(@status) end it "should raise an error if /bin/svcs does not exist" do File.should_receive(:exists?).with("/bin/svcs").and_return(false) lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Service) end describe "on a host with /bin/svcs" do before do File.stub!(:exists?).with('/bin/svcs').and_return(true) end describe "when discovering the current service state" do it "should create a current resource with the name of the new resource" do @provider.stub!(:popen4).with("/bin/svcs -l chef").and_return(@status) Chef::Resource::Service.should_receive(:new).and_return(@current_resource) @provider.load_current_resource end it "should return the current resource" do @provider.stub!(:popen4).with("/bin/svcs -l chef").and_return(@status) @provider.load_current_resource.should eql(@current_resource) end it "should popen4 '/bin/svcs -l service_name'" do @provider.should_receive(:popen4).with("/bin/svcs -l chef").and_return(@status) @provider.load_current_resource end it "should mark service as not running" do @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @current_resource.should_receive(:running).with(false) @provider.load_current_resource end it "should mark service as running" do @stdout.stub!(:each).and_yield("state online") @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @current_resource.should_receive(:running).with(true) @provider.load_current_resource end end describe "when enabling the service" do before(:each) do @provider.current_resource = @current_resource @current_resource.enabled(true) end it "should call svcadm enable -s chef" do @new_resource.stub!(:enable_command).and_return("#{@new_resource.enable_command}") @provider.should_receive(:shell_out!).with("/usr/sbin/svcadm enable -s #{@current_resource.service_name}").and_return(@status) @provider.enable_service.should be_true @current_resource.enabled.should be_true end it "should call svcadm enable -s chef for start_service" do @new_resource.stub!(:start_command).and_return("#{@new_resource.start_command}") @provider.should_receive(:shell_out!).with("/usr/sbin/svcadm enable -s #{@current_resource.service_name}").and_return(@status) @provider.start_service.should be_true @current_resource.enabled.should be_true end end describe "when disabling the service" do before(:each) do @provider.current_resource = @current_resource @current_resource.enabled(false) end it "should call svcadm disable -s chef" do @provider.should_receive(:shell_out!).with("/usr/sbin/svcadm disable -s chef").and_return(@status) @provider.disable_service.should be_true @current_resource.enabled.should be_false end it "should call svcadm disable -s chef for stop_service" do @provider.should_receive(:shell_out!).with("/usr/sbin/svcadm disable -s chef") @provider.stop_service.should be_true @current_resource.enabled.should be_false end end describe "when reloading the service" do before(:each) do @status = mock("Process::Status", :exitstatus => 0) @provider.current_resource = @current_resource end it "should call svcadm refresh chef" do @provider.should_receive(:shell_out!).with("/usr/sbin/svcadm refresh chef").and_return(@status) @provider.reload_service end end end end chef-11.8.2/spec/unit/provider/service/init_service_spec.rb0000644000004100000410000002153112254362222023767 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Service::Init, "load_current_resource" do before(:each) do @node = Chef::Node.new @node.automatic_attrs[:command] = {:ps => "ps -ef"} @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Service.new("chef") @current_resource = Chef::Resource::Service.new("chef") @provider = Chef::Provider::Service::Init.new(@new_resource, @run_context) Chef::Resource::Service.stub!(:new).and_return(@current_resource) @stdout = StringIO.new(<<-PS) aj 7842 5057 0 21:26 pts/2 00:00:06 vi init.rb aj 7903 5016 0 21:26 pts/5 00:00:00 /bin/bash aj 8119 6041 0 21:34 pts/3 00:00:03 vi init_service_spec.rb PS @status = mock("Status", :exitstatus => 0, :stdout => @stdout) @provider.stub!(:shell_out!).and_return(@status) end it "should create a current resource with the name of the new resource" do @provider.load_current_resource @provider.current_resource.should equal(@current_resource) end it "should set the current resources service name to the new resources service name" do @provider.load_current_resource @current_resource.service_name.should == 'chef' end describe "when the service supports status" do before do @new_resource.supports({:status => true}) end it "should run '/etc/init.d/service_name status'" do @provider.should_receive(:shell_out).with("/etc/init.d/#{@current_resource.service_name} status").and_return(@status) @provider.load_current_resource end it "should set running to true if the status command returns 0" do @provider.stub!(:shell_out).with("/etc/init.d/#{@current_resource.service_name} status").and_return(@status) @provider.load_current_resource @current_resource.running.should be_true end it "should set running to false if the status command returns anything except 0" do @status.stub!(:exitstatus).and_return(1) @provider.stub!(:shell_out).with("/etc/init.d/#{@current_resource.service_name} status").and_return(@status) @provider.load_current_resource @current_resource.running.should be_false end it "should set running to false if the status command raises" do @provider.stub!(:shell_out).and_raise(Mixlib::ShellOut::ShellCommandFailed) @provider.load_current_resource @current_resource.running.should be_false end end describe "when a status command has been specified" do before do @new_resource.stub!(:status_command).and_return("/etc/init.d/chefhasmonkeypants status") end it "should run the services status command if one has been specified" do @provider.should_receive(:shell_out).with("/etc/init.d/chefhasmonkeypants status").and_return(@status) @provider.load_current_resource end end describe "when an init command has been specified" do before do @new_resource.stub!(:init_command).and_return("/opt/chef-server/service/erchef") @provider = Chef::Provider::Service::Init.new(@new_resource, @run_context) end it "should use the init_command if one has been specified" do @provider.should_receive(:shell_out!).with("/opt/chef-server/service/erchef start") @provider.start_service end end describe "when the node has not specified a ps command" do it "should raise an error if the node has a nil ps attribute" do @node.automatic_attrs[:command] = {:ps => nil} @provider.load_current_resource @provider.action = :start @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end it "should raise an error if the node has an empty ps attribute" do @node.automatic_attrs[:command] = {:ps => ""} @provider.load_current_resource @provider.action = :start @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end end describe "when we have a 'ps' attribute" do it "should shell_out! the node's ps command" do @provider.should_receive(:shell_out!).and_return(@status) @provider.load_current_resource end it "should set running to true if the regex matches the output" do @stdout = StringIO.new(<<-RUNNING_PS) aj 7842 5057 0 21:26 pts/2 00:00:06 chef aj 7842 5057 0 21:26 pts/2 00:00:06 poos RUNNING_PS @status.stub!(:stdout).and_return(@stdout) @provider.load_current_resource @current_resource.running.should be_true end it "should set running to false if the regex doesn't match" do @provider.stub!(:shell_out!).and_return(@status) @provider.load_current_resource @current_resource.running.should be_false end it "should raise an exception if ps fails" do @provider.stub!(:shell_out!).and_raise(Mixlib::ShellOut::ShellCommandFailed) @provider.load_current_resource @provider.action = :start @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end end it "should return the current resource" do @provider.load_current_resource.should eql(@current_resource) end describe "when starting the service" do it "should call the start command if one is specified" do @new_resource.start_command("/etc/init.d/chef startyousillysally") @provider.should_receive(:shell_out!).with("/etc/init.d/chef startyousillysally") @provider.start_service() end it "should call '/etc/init.d/service_name start' if no start command is specified" do @provider.should_receive(:shell_out!).with("/etc/init.d/#{@new_resource.service_name} start") @provider.start_service() end end describe Chef::Provider::Service::Init, "stop_service" do it "should call the stop command if one is specified" do @new_resource.stop_command("/etc/init.d/chef itoldyoutostop") @provider.should_receive(:shell_out!).with("/etc/init.d/chef itoldyoutostop") @provider.stop_service() end it "should call '/etc/init.d/service_name stop' if no stop command is specified" do @provider.should_receive(:shell_out!).with("/etc/init.d/#{@new_resource.service_name} stop") @provider.stop_service() end end describe "when restarting a service" do it "should call 'restart' on the service_name if the resource supports it" do @new_resource.supports({:restart => true}) @provider.should_receive(:shell_out!).with("/etc/init.d/#{@new_resource.service_name} restart") @provider.restart_service() end it "should call the restart_command if one has been specified" do @new_resource.restart_command("/etc/init.d/chef restartinafire") @provider.should_receive(:shell_out!).with("/etc/init.d/#{@new_resource.service_name} restartinafire") @provider.restart_service() end it "should just call stop, then start when the resource doesn't support restart and no restart_command is specified" do @provider.should_receive(:stop_service) @provider.should_receive(:sleep).with(1) @provider.should_receive(:start_service) @provider.restart_service() end end describe "when reloading a service" do it "should call 'reload' on the service if it supports it" do @new_resource.supports({:reload => true}) @provider.should_receive(:shell_out!).with("/etc/init.d/chef reload") @provider.reload_service() end it "should should run the user specified reload command if one is specified and the service doesn't support reload" do @new_resource.reload_command("/etc/init.d/chef lollerpants") @provider.should_receive(:shell_out!).with("/etc/init.d/chef lollerpants") @provider.reload_service() end end describe "when a custom command has been specified" do before do @new_resource.start_command("/etc/init.d/chef startyousillysally") end it "should still pass all why run assertions" do lambda { @provider.run_action(:start) }.should_not raise_error(Chef::Exceptions::Service) end end end chef-11.8.2/spec/unit/provider/service/systemd_service_spec.rb0000644000004100000410000002471012254362222024516 0ustar www-datawww-data# # Author:: Stephen Haynes () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Service::Systemd do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Service.new('rsyslog.service') @provider = Chef::Provider::Service::Systemd.new(@new_resource, @run_context) end describe "load_current_resource" do before(:each) do @current_resource = Chef::Resource::Service.new('rsyslog.service') Chef::Resource::Service.stub!(:new).and_return(@current_resource) @provider.stub!(:is_active?).and_return(false) @provider.stub!(:is_enabled?).and_return(false) end it "should create a current resource with the name of the new resource" do Chef::Resource::Service.should_receive(:new).and_return(@current_resource) @provider.load_current_resource end it "should set the current resources service name to the new resources service name" do @current_resource.should_receive(:service_name).with(@new_resource.service_name) @provider.load_current_resource end it "should check if the service is running" do @provider.should_receive(:is_active?) @provider.load_current_resource end it "should set running to true if the service is running" do @provider.stub!(:is_active?).and_return(true) @current_resource.should_receive(:running).with(true) @provider.load_current_resource end it "should set running to false if the service is not running" do @provider.stub!(:is_active?).and_return(false) @current_resource.should_receive(:running).with(false) @provider.load_current_resource end describe "when a status command has been specified" do before do @new_resource.stub!(:status_command).and_return("/bin/chefhasmonkeypants status") end it "should run the services status command if one has been specified" do @provider.stub!(:run_command_with_systems_locale).with({:command => "/bin/chefhasmonkeypants status"}).and_return(0) @current_resource.should_receive(:running).with(true) @provider.load_current_resource end it "should run the services status command if one has been specified and properly set status check state" do @provider.stub!(:run_command_with_systems_locale).with({:command => "/bin/chefhasmonkeypants status"}).and_return(0) @provider.load_current_resource @provider.instance_variable_get("@status_check_success").should be_true end it "should set running to false if it catches a Chef::Exceptions::Exec when using a status command" do @provider.stub!(:run_command_with_systems_locale).and_raise(Chef::Exceptions::Exec) @current_resource.should_receive(:running).with(false) @provider.load_current_resource end it "should update state to indicate status check failed when an exception is thrown using a status command" do @provider.stub!(:run_command_with_systems_locale).and_raise(Chef::Exceptions::Exec) @provider.load_current_resource @provider.instance_variable_get("@status_check_success").should be_false end end it "should check if the service is enabled" do @provider.should_receive(:is_enabled?) @provider.load_current_resource end it "should set enabled to true if the service is enabled" do @provider.stub!(:is_enabled?).and_return(true) @current_resource.should_receive(:enabled).with(true) @provider.load_current_resource end it "should set enabled to false if the service is not enabled" do @provider.stub!(:is_enabled?).and_return(false) @current_resource.should_receive(:enabled).with(false) @provider.load_current_resource end it "should return the current resource" do @provider.load_current_resource.should eql(@current_resource) end end describe "start and stop service" do before(:each) do @current_resource = Chef::Resource::Service.new('rsyslog.service') Chef::Resource::Service.stub!(:new).and_return(@current_resource) @provider.current_resource = @current_resource end it "should call the start command if one is specified" do @new_resource.stub!(:start_command).and_return("/sbin/rsyslog startyousillysally") @provider.should_receive(:shell_out!).with("/sbin/rsyslog startyousillysally") @provider.start_service end it "should call '/bin/systemctl start service_name' if no start command is specified" do @provider.should_receive(:run_command_with_systems_locale).with({:command => "/bin/systemctl start #{@new_resource.service_name}"}).and_return(0) @provider.start_service end it "should not call '/bin/systemctl start service_name' if it is already running" do @current_resource.stub!(:running).and_return(true) @provider.should_not_receive(:run_command_with_systems_locale).with({:command => "/bin/systemctl start #{@new_resource.service_name}"}) @provider.start_service end it "should call the restart command if one is specified" do @current_resource.stub!(:running).and_return(true) @new_resource.stub!(:restart_command).and_return("/sbin/rsyslog restartyousillysally") @provider.should_receive(:shell_out!).with("/sbin/rsyslog restartyousillysally") @provider.restart_service end it "should call '/bin/systemctl restart service_name' if no restart command is specified" do @current_resource.stub!(:running).and_return(true) @provider.should_receive(:run_command_with_systems_locale).with({:command => "/bin/systemctl restart #{@new_resource.service_name}"}).and_return(0) @provider.restart_service end it "should call the reload command if one is specified" do @current_resource.stub!(:running).and_return(true) @new_resource.stub!(:reload_command).and_return("/sbin/rsyslog reloadyousillysally") @provider.should_receive(:shell_out!).with("/sbin/rsyslog reloadyousillysally") @provider.reload_service end it "should call '/bin/systemctl reload service_name' if no reload command is specified" do @current_resource.stub!(:running).and_return(true) @provider.should_receive(:run_command_with_systems_locale).with({:command => "/bin/systemctl reload #{@new_resource.service_name}"}).and_return(0) @provider.reload_service end it "should call the stop command if one is specified" do @current_resource.stub!(:running).and_return(true) @new_resource.stub!(:stop_command).and_return("/sbin/rsyslog stopyousillysally") @provider.should_receive(:shell_out!).with("/sbin/rsyslog stopyousillysally") @provider.stop_service end it "should call '/bin/systemctl stop service_name' if no stop command is specified" do @current_resource.stub!(:running).and_return(true) @provider.should_receive(:run_command_with_systems_locale).with({:command => "/bin/systemctl stop #{@new_resource.service_name}"}).and_return(0) @provider.stop_service end it "should not call '/bin/systemctl stop service_name' if it is already stopped" do @current_resource.stub!(:running).and_return(false) @provider.should_not_receive(:run_command_with_systems_locale).with({:command => "/bin/systemctl stop #{@new_resource.service_name}"}) @provider.stop_service end end describe "enable and disable service" do before(:each) do @current_resource = Chef::Resource::Service.new('rsyslog.service') Chef::Resource::Service.stub!(:new).and_return(@current_resource) @provider.current_resource = @current_resource end it "should call '/bin/systemctl enable service_name' to enable the service" do @provider.should_receive(:run_command_with_systems_locale).with({:command => "/bin/systemctl enable #{@new_resource.service_name}"}).and_return(0) @provider.enable_service end it "should call '/bin/systemctl disable service_name' to disable the service" do @provider.should_receive(:run_command_with_systems_locale).with({:command => "/bin/systemctl disable #{@new_resource.service_name}"}).and_return(0) @provider.disable_service end end describe "is_active?" do before(:each) do @current_resource = Chef::Resource::Service.new('rsyslog.service') Chef::Resource::Service.stub!(:new).and_return(@current_resource) end it "should return true if '/bin/systemctl is-active service_name' returns 0" do @provider.should_receive(:run_command_with_systems_locale).with({:command => '/bin/systemctl is-active rsyslog.service', :ignore_failure => true}).and_return(0) @provider.is_active?.should be_true end it "should return false if '/bin/systemctl is-active service_name' returns anything except 0" do @provider.should_receive(:run_command_with_systems_locale).with({:command => '/bin/systemctl is-active rsyslog.service', :ignore_failure => true}).and_return(1) @provider.is_active?.should be_false end end describe "is_enabled?" do before(:each) do @current_resource = Chef::Resource::Service.new('rsyslog.service') Chef::Resource::Service.stub!(:new).and_return(@current_resource) end it "should return true if '/bin/systemctl is-enabled service_name' returns 0" do @provider.should_receive(:run_command_with_systems_locale).with({:command => '/bin/systemctl is-enabled rsyslog.service', :ignore_failure => true}).and_return(0) @provider.is_enabled?.should be_true end it "should return false if '/bin/systemctl is-enabled service_name' returns anything except 0" do @provider.should_receive(:run_command_with_systems_locale).with({:command => '/bin/systemctl is-enabled rsyslog.service', :ignore_failure => true}).and_return(1) @provider.is_enabled?.should be_false end end end chef-11.8.2/spec/unit/provider/service/simple_service_spec.rb0000644000004100000410000001551112254362222024316 0ustar www-datawww-data# # Author:: Mathieu Sauve-Frankel # Copyright:: Copyright (c) 2009, Mathieu Sauve Frankel # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Service::Simple, "load_current_resource" do before(:each) do @node = Chef::Node.new @node.automatic_attrs[:command] = {:ps => "ps -ef"} @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Service.new("chef") @current_resource = Chef::Resource::Service.new("chef") @provider = Chef::Provider::Service::Simple.new(@new_resource, @run_context) Chef::Resource::Service.stub!(:new).and_return(@current_resource) @stdout = StringIO.new(<<-NOMOCKINGSTRINGSPLZ) aj 7842 5057 0 21:26 pts/2 00:00:06 vi init.rb aj 7903 5016 0 21:26 pts/5 00:00:00 /bin/bash aj 8119 6041 0 21:34 pts/3 00:00:03 vi simple_service_spec.rb NOMOCKINGSTRINGSPLZ @status = mock("Status", :exitstatus => 0, :stdout => @stdout) @provider.stub!(:shell_out!).and_return(@status) end it "should create a current resource with the name of the new resource" do Chef::Resource::Service.should_receive(:new).and_return(@current_resource) @provider.load_current_resource end it "should set the current resources service name to the new resources service name" do @current_resource.should_receive(:service_name).with(@new_resource.service_name) @provider.load_current_resource end it "should raise error if the node has a nil ps attribute and no other means to get status" do @node.automatic_attrs[:command] = {:ps => nil} @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end it "should raise error if the node has an empty ps attribute and no other means to get status" do @node.automatic_attrs[:command] = {:ps => ""} @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end describe "when we have a 'ps' attribute" do it "should shell_out! the node's ps command" do @provider.should_receive(:shell_out!).with(@node[:command][:ps]).and_return(@status) @provider.load_current_resource end it "should read stdout of the ps command" do @provider.stub!(:shell_out!).and_return(@status) @stdout.should_receive(:each_line).and_return(true) @provider.load_current_resource end it "should set running to true if the regex matches the output" do @stdout = StringIO.new(<<-NOMOCKINGSTRINGSPLZ) aj 7842 5057 0 21:26 pts/2 00:00:06 chef aj 7842 5057 0 21:26 pts/2 00:00:06 poos NOMOCKINGSTRINGSPLZ @status = mock("Status", :exitstatus => 0, :stdout => @stdout) @provider.stub!(:shell_out!).and_return(@status) @provider.load_current_resource @current_resource.running.should be_true end it "should set running to false if the regex doesn't match" do @provider.stub!(:shell_out!).and_return(@status) @provider.load_current_resource @current_resource.running.should be_false end it "should raise an exception if ps fails" do @provider.stub!(:shell_out!).and_raise(Mixlib::ShellOut::ShellCommandFailed) @provider.action = :start @provider.load_current_resource @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end end it "should return the current resource" do @provider.load_current_resource.should eql(@current_resource) end describe "when starting the service" do it "should call the start command if one is specified" do @new_resource.stub!(:start_command).and_return("#{@new_resource.start_command}") @provider.should_receive(:shell_out!).with("#{@new_resource.start_command}") @provider.start_service() end it "should raise an exception if no start command is specified" do @provider.define_resource_requirements @provider.action = :start lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end end describe "when stopping a service" do it "should call the stop command if one is specified" do @new_resource.stop_command("/etc/init.d/themadness stop") @provider.should_receive(:shell_out!).with("/etc/init.d/themadness stop") @provider.stop_service() end it "should raise an exception if no stop command is specified" do @provider.define_resource_requirements @provider.action = :stop lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end end describe Chef::Provider::Service::Simple, "restart_service" do it "should call the restart command if one has been specified" do @new_resource.restart_command("/etc/init.d/foo restart") @provider.should_receive(:shell_out!).with("/etc/init.d/foo restart") @provider.restart_service() end it "should raise an exception if the resource doesn't support restart, no restart command is provided, and no stop command is provided" do @provider.define_resource_requirements @provider.action = :restart lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end it "should just call stop, then start when the resource doesn't support restart and no restart_command is specified" do @provider.should_receive(:stop_service) @provider.should_receive(:sleep).with(1) @provider.should_receive(:start_service) @provider.restart_service() end end describe Chef::Provider::Service::Simple, "reload_service" do it "should raise an exception if reload is requested but no command is specified" do @provider.define_resource_requirements @provider.action = :reload lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::UnsupportedAction) end it "should should run the user specified reload command if one is specified" do @new_resource.reload_command("kill -9 1") @provider.should_receive(:shell_out!).with("kill -9 1") @provider.reload_service() end end end chef-11.8.2/spec/unit/provider/service/invokercd_service_spec.rb0000644000004100000410000002115212254362222025007 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Service::Invokercd, "load_current_resource" do before(:each) do @node = Chef::Node.new @node.automatic_attrs[:command] = {:ps => "ps -ef"} @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Service.new("chef") @current_resource = Chef::Resource::Service.new("chef") @provider = Chef::Provider::Service::Invokercd.new(@new_resource, @run_context) Chef::Resource::Service.stub!(:new).and_return(@current_resource) @stdout = StringIO.new(<<-PS) aj 7842 5057 0 21:26 pts/2 00:00:06 vi init.rb aj 7903 5016 0 21:26 pts/5 00:00:00 /bin/bash aj 8119 6041 0 21:34 pts/3 00:00:03 vi init_service_spec.rb PS @status = mock("Status", :exitstatus => 0, :stdout => @stdout) @provider.stub!(:shell_out!).and_return(@status) end it "should create a current resource with the name of the new resource" do @provider.load_current_resource @provider.current_resource.should equal(@current_resource) end it "should set the current resources service name to the new resources service name" do @provider.load_current_resource @current_resource.service_name.should == 'chef' end describe "when the service supports status" do before do @new_resource.supports({:status => true}) end it "should run '/usr/sbin/invoke-rc.d service_name status'" do @provider.should_receive(:shell_out).with("/usr/sbin/invoke-rc.d #{@current_resource.service_name} status").and_return(@status) @provider.load_current_resource end it "should set running to true if the status command returns 0" do @provider.stub!(:shell_out).with("/usr/sbin/invoke-rc.d #{@current_resource.service_name} status").and_return(@status) @provider.load_current_resource @current_resource.running.should be_true end it "should set running to false if the status command returns anything except 0" do @status.stub!(:exitstatus).and_return(1) @provider.stub!(:shell_out).with("/usr/sbin/invoke-rc.d #{@current_resource.service_name} status").and_return(@status) @provider.load_current_resource @current_resource.running.should be_false end it "should set running to false if the status command raises" do @provider.stub!(:shell_out).with("/usr/sbin/invoke-rc.d #{@current_resource.service_name} status").and_raise(Mixlib::ShellOut::ShellCommandFailed) @provider.load_current_resource @current_resource.running.should be_false end end describe "when a status command has been specified" do before do @new_resource.stub!(:status_command).and_return("/usr/sbin/invoke-rc.d chefhasmonkeypants status") end it "should run the services status command if one has been specified" do @provider.should_receive(:shell_out).with("/usr/sbin/invoke-rc.d chefhasmonkeypants status").and_return(@status) @provider.load_current_resource end end describe "when the node has not specified a ps command" do it "should raise error if the node has a nil ps attribute and no other means to get status" do @node.automatic_attrs[:command] = {:ps => nil} @provider.action = :start @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end it "should raise error if the node has an empty ps attribute and no other means to get status" do @node.automatic_attrs[:command] = {:ps => ""} @provider.action = :start @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end end describe "when we have a 'ps' attribute" do it "should shell_out! the node's ps command" do @status = mock("Status", :exitstatus => 0, :stdout => @stdout) @provider.should_receive(:shell_out!).with(@node[:command][:ps]).and_return(@status) @provider.load_current_resource end it "should set running to true if the regex matches the output" do @stdout = StringIO.new(<<-RUNNING_PS) aj 7842 5057 0 21:26 pts/2 00:00:06 chef aj 7842 5057 0 21:26 pts/2 00:00:06 poos RUNNING_PS @status = mock("Status", :exitstatus => 0, :stdout => @stdout) @provider.should_receive(:shell_out!).and_return(@status) @provider.load_current_resource @current_resource.running.should be_true end it "should set running to false if the regex doesn't match" do @status = mock("Status", :exitstatus => 0, :stdout => @stdout) @provider.should_receive(:shell_out!).and_return(@status) @provider.load_current_resource @current_resource.running.should be_false end it "should raise an exception if ps fails" do @provider.stub!(:shell_out!).and_raise(Mixlib::ShellOut::ShellCommandFailed) @provider.action = :start @provider.load_current_resource @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end end it "should return the current resource" do @provider.load_current_resource.should eql(@current_resource) end describe "when starting the service" do it "should call the start command if one is specified" do @new_resource.start_command("/usr/sbin/invoke-rc.d chef startyousillysally") @provider.should_receive(:shell_out!).with("/usr/sbin/invoke-rc.d chef startyousillysally") @provider.start_service() end it "should call '/usr/sbin/invoke-rc.d service_name start' if no start command is specified" do @provider.should_receive(:shell_out!).with("/usr/sbin/invoke-rc.d #{@new_resource.service_name} start") @provider.start_service() end end describe Chef::Provider::Service::Invokercd, "stop_service" do it "should call the stop command if one is specified" do @new_resource.stop_command("/usr/sbin/invoke-rc.d chef itoldyoutostop") @provider.should_receive(:shell_out!).with("/usr/sbin/invoke-rc.d chef itoldyoutostop") @provider.stop_service() end it "should call '/usr/sbin/invoke-rc.d service_name stop' if no stop command is specified" do @provider.should_receive(:shell_out!).with("/usr/sbin/invoke-rc.d #{@new_resource.service_name} stop") @provider.stop_service() end end describe "when restarting a service" do it "should call 'restart' on the service_name if the resource supports it" do @new_resource.supports({:restart => true}) @provider.should_receive(:shell_out!).with("/usr/sbin/invoke-rc.d #{@new_resource.service_name} restart") @provider.restart_service() end it "should call the restart_command if one has been specified" do @new_resource.restart_command("/usr/sbin/invoke-rc.d chef restartinafire") @provider.should_receive(:shell_out!).with("/usr/sbin/invoke-rc.d #{@new_resource.service_name} restartinafire") @provider.restart_service() end it "should just call stop, then start when the resource doesn't support restart and no restart_command is specified" do @provider.should_receive(:stop_service) @provider.should_receive(:sleep).with(1) @provider.should_receive(:start_service) @provider.restart_service() end end describe "when reloading a service" do it "should call 'reload' on the service if it supports it" do @new_resource.supports({:reload => true}) @provider.should_receive(:shell_out!).with("/usr/sbin/invoke-rc.d chef reload") @provider.reload_service() end it "should should run the user specified reload command if one is specified and the service doesn't support reload" do @new_resource.reload_command("/usr/sbin/invoke-rc.d chef lollerpants") @provider.should_receive(:shell_out!).with("/usr/sbin/invoke-rc.d chef lollerpants") @provider.reload_service() end end end chef-11.8.2/spec/unit/provider/service/macosx_spec.rb0000644000004100000410000002214212254362222022575 0ustar www-datawww-data# # Author:: Igor Afonov # Copyright:: Copyright (c) 2011 Igor Afonov # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Service::Macosx do describe ".gather_plist_dirs" do context "when HOME directory is set" do before do ENV.stub(:[]).with('HOME').and_return("/User/someuser") end it "includes users's LaunchAgents folder" do described_class.gather_plist_dirs.should include("#{ENV['HOME']}/Library/LaunchAgents") end end context "when HOME directory is not set" do before do ENV.stub(:[]).with('HOME').and_return(nil) end it "doesn't include user's LaunchAgents folder" do described_class.gather_plist_dirs.should_not include("~/Library/LaunchAgents") end end end context "when service name is given as" do let(:node) { Chef::Node.new } let(:events) {Chef::EventDispatch::Dispatcher.new} let(:run_context) { Chef::RunContext.new(node, {}, events) } let(:provider) { described_class.new(new_resource, run_context) } let(:stdout) { StringIO.new } ["redis-server", "io.redis.redis-server"].each do |service_name| before do Dir.stub!(:glob).and_return(["/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist"], []) provider.stub!(:shell_out!). with("launchctl list", {:group => 1001, :user => 101}). and_return(mock("ouput", :stdout => stdout)) File.stub!(:stat).and_return(mock("stat", :gid => 1001, :uid => 101)) end context "#{service_name}" do let(:new_resource) { Chef::Resource::Service.new(service_name) } let!(:current_resource) { Chef::Resource::Service.new(service_name) } describe "#load_current_resource" do context "when launchctl returns pid in service list" do let(:stdout) { StringIO.new <<-SVC_LIST } 12761 - 0x100114220.old.machinit.thing 7777 - io.redis.redis-server - - com.lol.stopped-thing SVC_LIST before do provider.load_current_resource end it "sets resource running state to true" do provider.current_resource.running.should be_true end it "sets resouce enabled state to true" do provider.current_resource.enabled.should be_true end end describe "running unsupported actions" do before do Dir.stub!(:glob).and_return(["/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist"], []) end it "should throw an exception when enable action is attempted" do lambda {provider.run_action(:enable)}.should raise_error(Chef::Exceptions::UnsupportedAction) end it "should throw an exception when reload action is attempted" do lambda {provider.run_action(:reload)}.should raise_error(Chef::Exceptions::UnsupportedAction) end it "should throw an exception when disable action is attempted" do lambda {provider.run_action(:disable)}.should raise_error(Chef::Exceptions::UnsupportedAction) end end context "when launchctl returns empty service pid" do let(:stdout) { StringIO.new <<-SVC_LIST } 12761 - 0x100114220.old.machinit.thing - - io.redis.redis-server - - com.lol.stopped-thing SVC_LIST before do provider.load_current_resource end it "sets resource running state to false" do provider.current_resource.running.should be_false end it "sets resouce enabled state to true" do provider.current_resource.enabled.should be_true end end context "when launchctl doesn't return service entry at all" do let(:stdout) { StringIO.new <<-SVC_LIST } 12761 - 0x100114220.old.machinit.thing - - com.lol.stopped-thing SVC_LIST it "sets service running state to false" do provider.load_current_resource provider.current_resource.running.should be_false end context "and plist for service is not available" do before do Dir.stub!(:glob).and_return([]) provider.load_current_resource end it "sets resouce enabled state to false" do provider.current_resource.enabled.should be_false end end context "and plist for service is available" do before do Dir.stub!(:glob).and_return(["/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist"], []) provider.load_current_resource end it "sets resouce enabled state to true" do provider.current_resource.enabled.should be_true end end describe "and several plists match service name" do it "throws exception" do Dir.stub!(:glob).and_return(["/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist", "/Users/wtf/something.plist"]) provider.load_current_resource provider.define_resource_requirements lambda { provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end end end end describe "#start_service" do before do Chef::Resource::Service.stub!(:new).and_return(current_resource) provider.load_current_resource current_resource.stub!(:running).and_return(false) end it "calls the start command if one is specified and service is not running" do new_resource.stub!(:start_command).and_return("cowsay dirty") provider.should_receive(:shell_out!).with("cowsay dirty") provider.start_service end it "shows warning message if service is already running" do current_resource.stub!(:running).and_return(true) Chef::Log.should_receive(:debug).with("service[#{service_name}] already running, not starting") provider.start_service end it "starts service via launchctl if service found" do provider.should_receive(:shell_out!). with("launchctl load -w '/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist'", :group => 1001, :user => 101). and_return(0) provider.start_service end end describe "#stop_service" do before do Chef::Resource::Service.stub!(:new).and_return(current_resource) provider.load_current_resource current_resource.stub!(:running).and_return(true) end it "calls the stop command if one is specified and service is running" do new_resource.stub!(:stop_command).and_return("kill -9 123") provider.should_receive(:shell_out!).with("kill -9 123") provider.stop_service end it "shows warning message if service is not running" do current_resource.stub!(:running).and_return(false) Chef::Log.should_receive(:debug).with("service[#{service_name}] not running, not stopping") provider.stop_service end it "stops the service via launchctl if service found" do provider.should_receive(:shell_out!). with("launchctl unload '/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist'", :group => 1001, :user => 101). and_return(0) provider.stop_service end end describe "#restart_service" do before do Chef::Resource::Service.stub!(:new).and_return(current_resource) provider.load_current_resource current_resource.stub!(:running).and_return(true) provider.stub!(:sleep) end it "issues a command if given" do new_resource.stub!(:restart_command).and_return("reload that thing") provider.should_receive(:shell_out!).with("reload that thing") provider.restart_service end it "stops and then starts service" do provider.should_receive(:stop_service) provider.should_receive(:start_service); provider.restart_service end end end end end end chef-11.8.2/spec/unit/provider/service/redhat_spec.rb0000644000004100000410000001611212254362222022552 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 HJK Solutions, LLC # License:: Apache License, Version 2.0 # # 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. # require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "spec_helper")) require 'ostruct' shared_examples_for "define_resource_requirements_common" do it "should raise an error if /sbin/chkconfig does not exist" do File.stub!(:exists?).with("/sbin/chkconfig").and_return(false) @provider.stub!(:shell_out).with("/sbin/service chef status").and_raise(Errno::ENOENT) @provider.stub!(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_raise(Errno::ENOENT) @provider.load_current_resource @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end it "should not raise an error if the service exists but is not added to any runlevels" do status = mock("Status", :exitstatus => 0, :stdout => "" , :stderr => "") @provider.should_receive(:shell_out).with("/sbin/service chef status").and_return(status) chkconfig = mock("Chkconfig", :exitstatus => 0, :stdout => "", :stderr => "service chef supports chkconfig, but is not referenced in any runlevel (run 'chkconfig --add chef')") @provider.should_receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig) @provider.load_current_resource @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should_not raise_error end end describe "Chef::Provider::Service::Redhat" do before(:each) do @node = Chef::Node.new @node.automatic_attrs[:command] = {:ps => 'foo'} @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Service.new("chef") @current_resource = Chef::Resource::Service.new("chef") @provider = Chef::Provider::Service::Redhat.new(@new_resource, @run_context) @provider.action = :start Chef::Resource::Service.stub!(:new).and_return(@current_resource) File.stub!(:exists?).with("/sbin/chkconfig").and_return(true) end describe "while not in why run mode" do before(:each) do Chef::Config[:why_run] = false end describe "load current resource" do it "sets the current enabled status to true if the service is enabled for any run level" do status = mock("Status", :exitstatus => 0, :stdout => "" , :stderr => "") @provider.should_receive(:shell_out).with("/sbin/service chef status").and_return(status) chkconfig = mock("Chkconfig", :exitstatus => 0, :stdout => "chef 0:off 1:off 2:off 3:off 4:off 5:on 6:off", :stderr => "") @provider.should_receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig) @provider.instance_variable_get("@service_missing").should be_false @provider.load_current_resource @current_resource.enabled.should be_true end it "sets the current enabled status to false if the regex does not match" do status = mock("Status", :exitstatus => 0, :stdout => "" , :stderr => "") @provider.should_receive(:shell_out).with("/sbin/service chef status").and_return(status) chkconfig = mock("Chkconfig", :exitstatus => 0, :stdout => "chef 0:off 1:off 2:off 3:off 4:off 5:off 6:off", :stderr => "") @provider.should_receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig) @provider.instance_variable_get("@service_missing").should be_false @provider.load_current_resource.should eql(@current_resource) @current_resource.enabled.should be_false end end describe "define resource requirements" do it_should_behave_like "define_resource_requirements_common" context "when the service does not exist" do before do status = mock("Status", :exitstatus => 1, :stdout => "", :stderr => "chef: unrecognized service") @provider.should_receive(:shell_out).with("/sbin/service chef status").and_return(status) chkconfig = mock("Chkconfig", :existatus=> 1, :stdout => "", :stderr => "error reading information on service chef: No such file or directory") @provider.should_receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig) @provider.load_current_resource @provider.define_resource_requirements end [ "start", "reload", "restart", "enable" ].each do |action| it "should raise an error when the action is #{action}" do @provider.action = action lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) end end [ "stop", "disable" ].each do |action| it "should not raise an error when the action is #{action}" do @provider.action = action lambda { @provider.process_resource_requirements }.should_not raise_error end end end end end describe "while in why run mode" do before(:each) do Chef::Config[:why_run] = true end after do Chef::Config[:why_run] = false end describe "define resource requirements" do it_should_behave_like "define_resource_requirements_common" it "should not raise an error if the service does not exist" do status = mock("Status", :exitstatus => 1, :stdout => "", :stderr => "chef: unrecognized service") @provider.should_receive(:shell_out).with("/sbin/service chef status").and_return(status) chkconfig = mock("Chkconfig", :existatus=> 1, :stdout => "", :stderr => "error reading information on service chef: No such file or directory") @provider.should_receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig) @provider.load_current_resource @provider.define_resource_requirements lambda { @provider.process_resource_requirements }.should_not raise_error end end end describe "enable_service" do it "should call chkconfig to add 'service_name'" do @provider.should_receive(:shell_out!).with("/sbin/chkconfig #{@new_resource.service_name} on") @provider.enable_service end end describe "disable_service" do it "should call chkconfig to del 'service_name'" do @provider.should_receive(:shell_out!).with("/sbin/chkconfig #{@new_resource.service_name} off") @provider.disable_service end end end chef-11.8.2/spec/unit/provider/deploy_spec.rb0000644000004100000410000006740012254362222021145 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Deploy do before do @release_time = Time.utc( 2004, 8, 15, 16, 23, 42) Time.stub!(:now).and_return(@release_time) @expected_release_dir = "/my/deploy/dir/releases/20040815162342" @resource = Chef::Resource::Deploy.new("/my/deploy/dir") @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @provider = Chef::Provider::Deploy.new(@resource, @run_context) @provider.stub!(:release_slug) @provider.stub!(:release_path).and_return(@expected_release_dir) end it "loads scm resource" do @provider.scm_provider.should_receive(:load_current_resource) @provider.load_current_resource end it "supports :deploy and :rollback actions" do @provider.should respond_to(:action_deploy) @provider.should respond_to(:action_rollback) end context "when the deploy resource has a timeout attribute" do let(:ten_seconds) { 10 } before { @resource.timeout(ten_seconds) } it "relays the timeout to the scm resource" do @provider.scm_provider.new_resource.timeout.should == ten_seconds end end context "when the deploy resource has no timeout attribute" do it "should not set a timeout on the scm resource" do @provider.scm_provider.new_resource.timeout.should be_nil end end context "when the deploy_to dir does not exist yet" do before do FileUtils.should_receive(:mkdir_p).with(@resource.deploy_to).ordered FileUtils.should_receive(:mkdir_p).with(@resource.shared_path).ordered ::File.stub!(:directory?).and_return(false) @provider.stub(:symlink) @provider.stub(:migrate) @provider.stub(:copy_cached_repo) end it "creates deploy_to dir" do ::Dir.should_receive(:chdir).with(@expected_release_dir).exactly(4).times @provider.stub(:update_cached_repo) @provider.deploy end end it "does not create deploy_to dir if it exists" do ::File.stub!(:directory?).and_return(true) ::Dir.should_receive(:chdir).with(@expected_release_dir).exactly(4).times FileUtils.should_not_receive(:mkdir_p).with(@resource.deploy_to) FileUtils.should_not_receive(:mkdir_p).with(@resource.shared_path) @provider.stub(:copy_cached_repo) @provider.stub(:update_cached_repo) @provider.stub(:symlink) @provider.stub(:migrate) @provider.deploy end it "ensures the deploy_to dir ownership after the verfication that it exists" do ::Dir.should_receive(:chdir).with(@expected_release_dir).exactly(4).times @provider.should_receive(:verify_directories_exist).ordered @provider.should_receive(:enforce_ownership).ordered @provider.stub(:copy_cached_repo) @provider.stub(:update_cached_repo) @provider.stub(:install_gems) @provider.stub(:enforce_ownership) @provider.stub(:symlink) @provider.stub(:migrate) @provider.deploy end it "updates and copies the repo, then does a migrate, symlink, restart, restart, cleanup on deploy" do FileUtils.stub(:mkdir_p).with("/my/deploy/dir") FileUtils.stub(:mkdir_p).with("/my/deploy/dir/shared") @provider.should_receive(:enforce_ownership).twice @provider.should_receive(:update_cached_repo) @provider.should_receive(:copy_cached_repo) @provider.should_receive(:install_gems) @provider.should_receive(:callback).with(:before_migrate, nil) @provider.should_receive(:migrate) @provider.should_receive(:callback).with(:before_symlink, nil) @provider.should_receive(:symlink) @provider.should_receive(:callback).with(:before_restart, nil) @provider.should_receive(:restart) @provider.should_receive(:callback).with(:after_restart, nil) @provider.should_receive(:cleanup!) @provider.deploy end it "should not deploy if there is already a deploy at release_path, and it is the current release" do @provider.stub!(:all_releases).and_return([@expected_release_dir]) @provider.stub!(:current_release?).with(@expected_release_dir).and_return(true) @provider.should_not_receive(:deploy) @provider.run_action(:deploy) end it "should call action_rollback if there is already a deploy of this revision at release_path, and it is not the current release" do @provider.stub!(:all_releases).and_return([@expected_release_dir, "102021"]) @provider.stub!(:current_release?).with(@expected_release_dir).and_return(false) @provider.should_receive(:rollback_to).with(@expected_release_dir) @provider.should_receive(:current_release?) @provider.run_action(:deploy) end it "calls deploy when deploying a new release" do @provider.stub!(:all_releases).and_return([]) @provider.should_receive(:deploy) @provider.run_action(:deploy) end it "runs action svn_force_export when new_resource.svn_force_export is true" do @resource.svn_force_export true @provider.scm_provider.should_receive(:run_action).with(:force_export) @provider.update_cached_repo end it "Removes the old release before deploying when force deploying over it" do @provider.stub!(:all_releases).and_return([@expected_release_dir]) FileUtils.should_receive(:rm_rf).with(@expected_release_dir) @provider.should_receive(:deploy) @provider.run_action(:force_deploy) end it "deploys as normal when force deploying and there's no prior release at the same path" do @provider.stub!(:all_releases).and_return([]) @provider.should_receive(:deploy) @provider.run_action(:force_deploy) end it "dont care by default if error happens on deploy" do @provider.stub!(:all_releases).and_return(['previous_release']) @provider.stub!(:deploy).and_return{ raise "Unexpected error" } @provider.stub!(:previous_release_path).and_return('previous_release') @provider.should_not_receive(:rollback) lambda { @provider.run_action(:deploy) }.should raise_exception(RuntimeError, "Unexpected error") end it "rollbacks to previous release if error happens on deploy" do @resource.rollback_on_error true @provider.stub!(:all_releases).and_return(['previous_release']) @provider.stub!(:deploy).and_return{ raise "Unexpected error" } @provider.stub!(:previous_release_path).and_return('previous_release') @provider.should_receive(:rollback) lambda { @provider.run_action(:deploy) }.should raise_exception(RuntimeError, "Unexpected error") end describe "on systems without broken Dir.glob results" do it "sets the release path to the penultimate release when one is not specified, symlinks, and rm's the last release on rollback" do @provider.stub!(:release_path).and_return("/my/deploy/dir/releases/3") all_releases = ["/my/deploy/dir/releases/1", "/my/deploy/dir/releases/2", "/my/deploy/dir/releases/3", "/my/deploy/dir/releases/4", "/my/deploy/dir/releases/5"] Dir.stub!(:glob).with("/my/deploy/dir/releases/*").and_return(all_releases) @provider.should_receive(:symlink) FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/releases/4") FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/releases/5") @provider.run_action(:rollback) @provider.release_path.should eql("/my/deploy/dir/releases/3") end it "sets the release path to the specified release, symlinks, and rm's any newer releases on rollback" do @provider.unstub!(:release_path) all_releases = ["/my/deploy/dir/releases/20040815162342", "/my/deploy/dir/releases/20040700000000", "/my/deploy/dir/releases/20040600000000", "/my/deploy/dir/releases/20040500000000"].sort! Dir.stub!(:glob).with("/my/deploy/dir/releases/*").and_return(all_releases) @provider.should_receive(:symlink) FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/releases/20040815162342") @provider.run_action(:rollback) @provider.release_path.should eql("/my/deploy/dir/releases/20040700000000") end it "sets the release path to the penultimate release, symlinks, and rm's the last release on rollback" do @provider.unstub!(:release_path) all_releases = [ "/my/deploy/dir/releases/20040815162342", "/my/deploy/dir/releases/20040700000000", "/my/deploy/dir/releases/20040600000000", "/my/deploy/dir/releases/20040500000000"] Dir.stub!(:glob).with("/my/deploy/dir/releases/*").and_return(all_releases) @provider.should_receive(:symlink) FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/releases/20040815162342") @provider.run_action(:rollback) @provider.release_path.should eql("/my/deploy/dir/releases/20040700000000") end describe "if there are no releases to fallback to" do it "an exception is raised when there is only 1 release" do #@provider.unstub!(:release_path) -- unstub the release path on top to feed our own release path all_releases = [ "/my/deploy/dir/releases/20040815162342"] Dir.stub!(:glob).with("/my/deploy/dir/releases/*").and_return(all_releases) #@provider.should_receive(:symlink) #FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/releases/20040815162342") #@provider.run_action(:rollback) #@provider.release_path.should eql(NIL) -- no check needed since assertions will fail lambda { @provider.run_action(:rollback) }.should raise_exception(RuntimeError, "There is no release to rollback to!") end it "an exception is raised when there are no releases" do all_releases = [] Dir.stub!(:glob).with("/my/deploy/dir/releases/*").and_return(all_releases) lambda { @provider.run_action(:rollback) }.should raise_exception(RuntimeError, "There is no release to rollback to!") end end end describe "CHEF-628: on systems with broken Dir.glob results" do it "sets the release path to the penultimate release, symlinks, and rm's the last release on rollback" do @provider.unstub!(:release_path) all_releases = [ "/my/deploy/dir/releases/20040500000000", "/my/deploy/dir/releases/20040600000000", "/my/deploy/dir/releases/20040700000000", "/my/deploy/dir/releases/20040815162342" ] Dir.stub!(:glob).with("/my/deploy/dir/releases/*").and_return(all_releases) @provider.should_receive(:symlink) FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/releases/20040815162342") @provider.run_action(:rollback) @provider.release_path.should eql("/my/deploy/dir/releases/20040700000000") end end it "raises a runtime error when there's no release to rollback to" do all_releases = [] Dir.stub!(:glob).with("/my/deploy/dir/releases/*").and_return(all_releases) lambda {@provider.run_action(:rollback)}.should raise_error(RuntimeError) end it "runs the new resource collection in the runner during a callback" do @runner = mock("Runner") Chef::Runner.stub!(:new).and_return(@runner) @runner.should_receive(:converge) callback_code = Proc.new { :noop } @provider.callback(:whatevs, callback_code) end it "loads callback files from the release/ dir if the file exists" do foo_callback = @expected_release_dir + "/deploy/foo.rb" ::File.should_receive(:exist?).with(foo_callback).once.and_return(true) ::Dir.should_receive(:chdir).with(@expected_release_dir).and_yield @provider.should_receive(:from_file).with(foo_callback) @provider.callback(:foo, "deploy/foo.rb") end it "raises a runtime error if a callback file is explicitly specified but does not exist" do baz_callback = "/deploy/baz.rb" ::File.should_receive(:exist?).with("#{@expected_release_dir}/#{baz_callback}").and_return(false) @resource.before_migrate baz_callback @provider.define_resource_requirements @provider.action = :deploy lambda {@provider.process_resource_requirements}.should raise_error(RuntimeError) end it "runs a default callback if the callback code is nil" do bar_callback = @expected_release_dir + "/deploy/bar.rb" ::File.should_receive(:exist?).with(bar_callback).and_return(true) ::Dir.should_receive(:chdir).with(@expected_release_dir).and_yield @provider.should_receive(:from_file).with(bar_callback) @provider.callback(:bar, nil) end it "skips an eval callback if the file doesn't exist" do barbaz_callback = @expected_release_dir + "/deploy/barbaz.rb" ::File.should_receive(:exist?).with(barbaz_callback).and_return(false) ::Dir.should_receive(:chdir).with(@expected_release_dir).and_yield @provider.should_not_receive(:from_file) @provider.callback(:barbaz, nil) end # CHEF-3449 #converge_by is called in #recipe_eval and must happen in sequence # with the other calls to #converge_by to keep the train on the tracks it "evaluates a callback file before the corresponding step" do @provider.should_receive(:verify_directories_exist) @provider.should_receive(:update_cached_repo) @provider.should_receive(:enforce_ownership) @provider.should_receive(:copy_cached_repo) @provider.should_receive(:install_gems) @provider.should_receive(:enforce_ownership) @provider.should_receive(:converge_by).ordered # before_migrate @provider.should_receive(:migrate).ordered @provider.should_receive(:converge_by).ordered # before_symlink @provider.should_receive(:symlink).ordered @provider.should_receive(:converge_by).ordered # before_restart @provider.should_receive(:restart).ordered @provider.should_receive(:converge_by).ordered # after_restart @provider.should_receive(:cleanup!) @provider.deploy end it "gets a SCM provider as specified by its resource" do @provider.scm_provider.should be_an_instance_of(Chef::Provider::Git) @provider.scm_provider.new_resource.destination.should eql("/my/deploy/dir/shared/cached-copy") end it "syncs the cached copy of the repo" do @provider.scm_provider.should_receive(:run_action).with(:sync) @provider.update_cached_repo end it "makes a copy of the cached repo in releases dir" do FileUtils.should_receive(:mkdir_p).with("/my/deploy/dir/releases") FileUtils.should_receive(:cp_r).with("/my/deploy/dir/shared/cached-copy/.", @expected_release_dir, :preserve => true) @provider.copy_cached_repo end it "calls the internal callback :release_created when cleaning up the releases" do FileUtils.stub!(:mkdir_p) FileUtils.stub!(:cp_r) @provider.should_receive(:release_created) @provider.cleanup! end it "chowns the whole release dir to user and group specified in the resource" do @resource.user "foo" @resource.group "bar" FileUtils.should_receive(:chown_R).with("foo", "bar", "/my/deploy/dir") @provider.enforce_ownership end it "skips the migration when resource.migrate => false but runs symlinks before migration" do @resource.migrate false @provider.should_not_receive :run_command @provider.should_receive :run_symlinks_before_migrate @provider.migrate end it "links the database.yml and runs resource.migration_command when resource.migrate #=> true" do @resource.migrate true @resource.migration_command "migration_foo" @resource.user "deployNinja" @resource.group "deployNinjas" @resource.environment "RAILS_ENV" => "production" FileUtils.should_receive(:ln_sf).with("/my/deploy/dir/shared/config/database.yml", @expected_release_dir + "/config/database.yml") @provider.should_receive(:enforce_ownership) STDOUT.stub!(:tty?).and_return(true) Chef::Log.stub!(:info?).and_return(true) @provider.should_receive(:run_command).with(:command => "migration_foo", :cwd => @expected_release_dir, :user => "deployNinja", :group => "deployNinjas", :log_level => :info, :live_stream => STDOUT, :log_tag => "deploy[/my/deploy/dir]", :environment => {"RAILS_ENV"=>"production"}) @provider.migrate end it "purges the current release's /log /tmp/pids/ and /public/system directories" do FileUtils.should_receive(:rm_rf).with(@expected_release_dir + "/log") FileUtils.should_receive(:rm_rf).with(@expected_release_dir + "/tmp/pids") FileUtils.should_receive(:rm_rf).with(@expected_release_dir + "/public/system") @provider.purge_tempfiles_from_current_release end it "symlinks temporary files and logs from the shared dir into the current release" do FileUtils.stub(:mkdir_p).with(@resource.shared_path + "/system") FileUtils.stub(:mkdir_p).with(@resource.shared_path + "/pids") FileUtils.stub(:mkdir_p).with(@resource.shared_path + "/log") FileUtils.should_receive(:mkdir_p).with(@expected_release_dir + "/tmp") FileUtils.should_receive(:mkdir_p).with(@expected_release_dir + "/public") FileUtils.should_receive(:mkdir_p).with(@expected_release_dir + "/config") FileUtils.should_receive(:ln_sf).with("/my/deploy/dir/shared/system", @expected_release_dir + "/public/system") FileUtils.should_receive(:ln_sf).with("/my/deploy/dir/shared/pids", @expected_release_dir + "/tmp/pids") FileUtils.should_receive(:ln_sf).with("/my/deploy/dir/shared/log", @expected_release_dir + "/log") FileUtils.should_receive(:ln_sf).with("/my/deploy/dir/shared/config/database.yml", @expected_release_dir + "/config/database.yml") @provider.should_receive(:enforce_ownership) @provider.link_tempfiles_to_current_release end it "symlinks the current release dir into production" do FileUtils.should_receive(:rm_f).with("/my/deploy/dir/current") FileUtils.should_receive(:ln_sf).with(@expected_release_dir, "/my/deploy/dir/current") @provider.should_receive(:enforce_ownership) @provider.link_current_release_to_production end context "with a customized app layout" do before do @resource.purge_before_symlink(%w{foo bar}) @resource.create_dirs_before_symlink(%w{baz qux}) @resource.symlinks "foo/bar" => "foo/bar", "baz" => "qux/baz" @resource.symlink_before_migrate "radiohead/in_rainbows.yml" => "awesome" end it "purges the purge_before_symlink directories" do FileUtils.should_receive(:rm_rf).with(@expected_release_dir + "/foo") FileUtils.should_receive(:rm_rf).with(@expected_release_dir + "/bar") @provider.purge_tempfiles_from_current_release end it "symlinks files from the shared directory to the current release directory" do FileUtils.should_receive(:mkdir_p).with(@expected_release_dir + "/baz") FileUtils.should_receive(:mkdir_p).with(@expected_release_dir + "/qux") FileUtils.stub(:mkdir_p).with(@resource.shared_path + "/foo/bar") FileUtils.stub(:mkdir_p).with(@resource.shared_path + "/baz") FileUtils.should_receive(:ln_sf).with("/my/deploy/dir/shared/foo/bar", @expected_release_dir + "/foo/bar") FileUtils.should_receive(:ln_sf).with("/my/deploy/dir/shared/baz", @expected_release_dir + "/qux/baz") FileUtils.should_receive(:ln_sf).with("/my/deploy/dir/shared/radiohead/in_rainbows.yml", @expected_release_dir + "/awesome") @provider.should_receive(:enforce_ownership) @provider.link_tempfiles_to_current_release end end it "does nothing for restart if restart_command is empty" do @provider.should_not_receive(:run_command) @provider.restart end it "runs the restart command in the current application dir when the resource has a restart_command" do @resource.restart_command "restartcmd" @provider.should_receive(:run_command).with(:command => "restartcmd", :cwd => "/my/deploy/dir/current", :log_tag => "deploy[/my/deploy/dir]", :log_level => :debug) @provider.restart end it "lists all available releases" do all_releases = ["/my/deploy/dir/20040815162342", "/my/deploy/dir/20040700000000", "/my/deploy/dir/20040600000000", "/my/deploy/dir/20040500000000"].sort! Dir.should_receive(:glob).with("/my/deploy/dir/releases/*").and_return(all_releases) @provider.all_releases.should eql(all_releases) end it "removes all but the 5 newest releases" do all_releases = ["/my/deploy/dir/20040815162342", "/my/deploy/dir/20040700000000", "/my/deploy/dir/20040600000000", "/my/deploy/dir/20040500000000", "/my/deploy/dir/20040400000000", "/my/deploy/dir/20040300000000", "/my/deploy/dir/20040200000000", "/my/deploy/dir/20040100000000"].sort! @provider.stub!(:all_releases).and_return(all_releases) FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/20040100000000") FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/20040200000000") FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/20040300000000") @provider.cleanup! end it "removes all but a certain number of releases when the resource has a keep_releases" do @resource.keep_releases 7 all_releases = ["/my/deploy/dir/20040815162342", "/my/deploy/dir/20040700000000", "/my/deploy/dir/20040600000000", "/my/deploy/dir/20040500000000", "/my/deploy/dir/20040400000000", "/my/deploy/dir/20040300000000", "/my/deploy/dir/20040200000000", "/my/deploy/dir/20040100000000"].sort! @provider.stub!(:all_releases).and_return(all_releases) FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/20040100000000") @provider.cleanup! end it "fires a callback for :release_deleted when deleting an old release" do all_releases = ["/my/deploy/dir/20040815162342", "/my/deploy/dir/20040700000000", "/my/deploy/dir/20040600000000", "/my/deploy/dir/20040500000000", "/my/deploy/dir/20040400000000", "/my/deploy/dir/20040300000000"].sort! @provider.stub!(:all_releases).and_return(all_releases) FileUtils.stub!(:rm_rf) @provider.should_receive(:release_deleted).with("/my/deploy/dir/20040300000000") @provider.cleanup! end it "puts resource.to_hash in @configuration for backwards compat with capistano-esque deploy hooks" do @provider.instance_variable_get(:@configuration).should == @resource.to_hash end it "sets @configuration[:environment] to the value of RAILS_ENV for backwards compat reasons" do resource = Chef::Resource::Deploy.new("/my/deploy/dir") resource.environment "production" provider = Chef::Provider::Deploy.new(resource, @run_context) provider.instance_variable_get(:@configuration)[:environment].should eql("production") end it "shouldn't give a no method error on migrate if the environment is nil" do @provider.stub!(:enforce_ownership) @provider.stub!(:run_symlinks_before_migrate) @provider.stub!(:run_command) @provider.migrate end context "using inline recipes for callbacks" do it "runs an inline recipe with the provided block for :callback_name == {:recipe => &block} " do snitch = nil recipe_code = Proc.new {snitch = 42} #@provider.should_receive(:instance_eval).with(&recipe_code) @provider.callback(:whateverz, recipe_code) snitch.should == 42 end it "loads a recipe file from the specified path and from_file evals it" do ::File.should_receive(:exist?).with(@expected_release_dir + "/chefz/foobar_callback.rb").once.and_return(true) ::Dir.should_receive(:chdir).with(@expected_release_dir).and_yield @provider.should_receive(:from_file).with(@expected_release_dir + "/chefz/foobar_callback.rb") @provider.callback(:whateverz, "chefz/foobar_callback.rb") end it "instance_evals a block/proc for restart command" do snitch = nil restart_cmd = Proc.new {snitch = 42} @resource.restart(&restart_cmd) @provider.restart snitch.should == 42 end end describe "API bridge to capistrano" do it "defines sudo as a forwarder to execute" do @provider.should_receive(:execute).with("the moon, fool") @provider.sudo("the moon, fool") end it "defines run as a forwarder to execute, setting the user, group, cwd and environment to new_resource.user" do mock_execution = mock("Resource::Execute") @provider.should_receive(:execute).with("iGoToHell4this").and_return(mock_execution) @resource.user("notCoolMan") @resource.group("Ggroup") @resource.environment("APP_ENV" => 'staging') @resource.deploy_to("/my/app") mock_execution.should_receive(:user).with("notCoolMan") mock_execution.should_receive(:group).with("Ggroup") mock_execution.should_receive(:cwd){|*args| if args.empty? nil else args.size.should == 1 args.first.should == @provider.release_path end }.twice mock_execution.should_receive(:environment){ |*args| if args.empty? nil else args.size.should == 1 args.first.should == {"APP_ENV" => "staging"} end }.twice @provider.run("iGoToHell4this") end it "defines run as a forwarder to execute, setting cwd and environment but not override" do mock_execution = mock("Resource::Execute") @provider.should_receive(:execute).with("iGoToHell4this").and_return(mock_execution) @resource.user("notCoolMan") mock_execution.should_receive(:user).with("notCoolMan") mock_execution.should_receive(:cwd).with(no_args()).and_return("/some/value") mock_execution.should_receive(:environment).with(no_args()).and_return({}) @provider.run("iGoToHell4this") end it "converts sudo and run to exec resources in hooks" do runner = mock("tehRunner") Chef::Runner.stub!(:new).and_return(runner) snitch = nil @resource.user("tehCat") callback_code = Proc.new do snitch = 42 temp_collection = self.resource_collection run("tehMice") snitch = temp_collection.lookup("execute[tehMice]") end runner.should_receive(:converge) # @provider.callback(:phony, callback_code) snitch.should be_an_instance_of(Chef::Resource::Execute) snitch.user.should == "tehCat" end end describe "installing gems from a gems.yml" do before do ::File.stub!(:exist?).with("#{@expected_release_dir}/gems.yml").and_return(true) @gem_list = [{:name=>"eventmachine", :version=>"0.12.9"}] end it "reads a gems.yml file, creating gem providers for each with action :upgrade" do IO.should_receive(:read).with("#{@expected_release_dir}/gems.yml").and_return("cookie") YAML.should_receive(:load).with("cookie").and_return(@gem_list) gems = @provider.send(:gem_packages) gems.map { |g| g.action }.should == [[:install]] gems.map { |g| g.name }.should == %w{eventmachine} gems.map { |g| g.version }.should == %w{0.12.9} end it "takes a list of gem providers converges them" do IO.stub!(:read) YAML.stub!(:load).and_return(@gem_list) expected_gem_resources = @provider.send(:gem_packages).map { |r| [r.name, r.version] } gem_runner = @provider.send(:gem_resource_collection_runner) # no one has heard of defining == to be meaningful so I have use this monstrosity actual = gem_runner.run_context.resource_collection.all_resources.map { |r| [r.name, r.version] } actual.should == expected_gem_resources end end end chef-11.8.2/spec/unit/provider/cron/0000755000004100000410000000000012254362222017244 5ustar www-datawww-datachef-11.8.2/spec/unit/provider/cron/unix_spec.rb0000644000004100000410000001015612254362222021571 0ustar www-datawww-data# # Author:: Bryan McLellan (btm@loftninjas.org) # Author:: Toomas Pelberg (toomasp@gmx.net) # Copyright:: Copyright (c) 2009 Bryan McLellan # Copyright:: Copyright (c) 2010 Toomas Pelberg # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Cron::Unix do before do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Cron.new("cronhole some stuff") @new_resource.user "root" @new_resource.minute "30" @new_resource.command "/bin/true" @provider = Chef::Provider::Cron::Unix.new(@new_resource, @run_context) end it "should inherit from Chef::Provider:Cron" do @provider.should be_a(Chef::Provider::Cron) end describe "read_crontab" do before :each do @status = mock("Status", :exitstatus => 0) @stdout = StringIO.new(<<-CRONTAB) 0 2 * * * /some/other/command # Chef Name: something else * 5 * * * /bin/true # Another comment CRONTAB @provider.stub!(:popen4).and_yield(1234, StringIO.new, @stdout, StringIO.new).and_return(@status) end it "should call crontab -l with the user" do @provider.should_receive(:popen4).with("crontab -l #{@new_resource.user}").and_return(@status) @provider.send(:read_crontab) end it "should return the contents of the crontab" do crontab = @provider.send(:read_crontab) crontab.should == <<-CRONTAB 0 2 * * * /some/other/command # Chef Name: something else * 5 * * * /bin/true # Another comment CRONTAB end it "should return nil if the user has no crontab" do status = mock("Status", :exitstatus => 1) @provider.stub!(:popen4).and_return(status) @provider.send(:read_crontab).should == nil end it "should raise an exception if another error occurs" do status = mock("Status", :exitstatus => 2) @provider.stub!(:popen4).and_return(status) lambda do @provider.send(:read_crontab) end.should raise_error(Chef::Exceptions::Cron, "Error determining state of #{@new_resource.name}, exit: 2") end end describe "write_crontab" do before :each do @status = mock("Status", :exitstatus => 0) @provider.stub!(:run_command_and_return_stdout_stderr).and_return(@status, String.new, String.new) @tempfile = mock("foo", :path => "/tmp/foo", :close => true) Tempfile.stub!(:new).and_return(@tempfile) @tempfile.should_receive(:flush) @tempfile.should_receive(:chmod).with(420) @tempfile.should_receive(:close!) end it "should call crontab for the user" do @provider.should_receive(:run_command_and_return_stdout_stderr).with(hash_including(:user => @new_resource.user)) @tempfile.should_receive(:<<).with("Foo") @provider.send(:write_crontab, "Foo") end it "should call crontab with a file containing the crontab" do @provider.should_receive(:run_command_and_return_stdout_stderr) do |args| (args[:command] =~ %r{\A/usr/bin/crontab (/\S+)\z}).should be_true $1.should == "/tmp/foo" @status end @tempfile.should_receive(:<<).with("Foo\n# wibble\n wah!!") @provider.send(:write_crontab, "Foo\n# wibble\n wah!!") end it "should raise an exception if the command returns non-zero" do @tempfile.should_receive(:<<).with("Foo") @status.stub!(:exitstatus).and_return(1) lambda do @provider.send(:write_crontab, "Foo") end.should raise_error(Chef::Exceptions::Cron, /Error updating state of #{@new_resource.name}, exit: 1/) end end end chef-11.8.2/spec/unit/provider/registry_key_spec.rb0000644000004100000410000002623712254362222022374 0ustar www-datawww-data# # Author:: Lamont Granquist (lamont@opscode.com) # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::RegistryKey do let(:testval1) { { :name => "one", :type => :string, :data => "1" } } let(:testval1_wrong_type) { { :name => "one", :type => :multi_string, :data => "1" } } let(:testval1_wrong_data) { { :name => "one", :type => :string, :data => "2" } } let(:testval2) { { :name => "two", :type => :string, :data => "2" } } let(:testkey1) { 'HKLM\Software\Opscode\Testing' } before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::RegistryKey.new("windows is fun", @run_context) @new_resource.key testkey1 @new_resource.values( testval1 ) @new_resource.recursive false @provider = Chef::Provider::RegistryKey.new(@new_resource, @run_context) @provider.stub!(:running_on_windows!).and_return(true) @double_registry = double(Chef::Win32::Registry) @provider.stub!(:registry).and_return(@double_registry) end describe "when first created" do end describe "executing load_current_resource" do describe "when the key exists" do before(:each) do @double_registry.should_receive(:key_exists?).with(testkey1).and_return(true) @double_registry.should_receive(:get_values).with(testkey1).and_return( testval2 ) @provider.load_current_resource end it "should set the key of the current resource to the key of the new resource" do @provider.current_resource.key.should == @new_resource.key end it "should set the architecture of the current resource to the architecture of the new resource" do @provider.current_resource.architecture.should == @new_resource.architecture end it "should set the recursive flag of the current resource to the recursive flag of the new resource" do @provider.current_resource.recursive.should == @new_resource.recursive end it "should set the values of the current resource to the values it got from the registry" do @provider.current_resource.values.should == [ testval2 ] end end describe "when the key does not exist" do before(:each) do @double_registry.should_receive(:key_exists?).with(testkey1).and_return(false) @provider.load_current_resource end it "should set the values in the current resource to empty array" do @provider.current_resource.values.should == [] end end end describe "action_create" do context "when the key exists" do before(:each) do @double_registry.should_receive(:key_exists?).twice.with(testkey1).and_return(true) end it "should do nothing if the key and the value both exist" do @double_registry.should_receive(:get_values).with(testkey1).and_return( testval1 ) @double_registry.should_not_receive(:set_value) @provider.load_current_resource @provider.action_create end it "should create the value if the key exists but the value does not" do @double_registry.should_receive(:get_values).with(testkey1).and_return( testval2 ) @double_registry.should_receive(:set_value).with(testkey1, testval1) @provider.load_current_resource @provider.action_create end it "should set the value if the key exists but the data does not match" do @double_registry.should_receive(:get_values).with(testkey1).and_return( testval1_wrong_data ) @double_registry.should_receive(:set_value).with(testkey1, testval1) @provider.load_current_resource @provider.action_create end it "should set the value if the key exists but the type does not match" do @double_registry.should_receive(:get_values).with(testkey1).and_return( testval1_wrong_type ) @double_registry.should_receive(:set_value).with(testkey1, testval1) @provider.load_current_resource @provider.action_create end end context "when the key exists and the values in the new resource are empty" do it "when a value is in the key, it should do nothing" do @provider.new_resource.values([]) @double_registry.should_receive(:key_exists?).twice.with(testkey1).and_return(true) @double_registry.should_receive(:get_values).with(testkey1).and_return( testval1 ) @double_registry.should_not_receive(:create_key) @double_registry.should_not_receive(:set_value) @provider.load_current_resource @provider.action_create end it "when no value is in the key, it should do nothing" do @provider.new_resource.values([]) @double_registry.should_receive(:key_exists?).twice.with(testkey1).and_return(true) @double_registry.should_receive(:get_values).with(testkey1).and_return( nil ) @double_registry.should_not_receive(:create_key) @double_registry.should_not_receive(:set_value) @provider.load_current_resource @provider.action_create end end context "when the key does not exist" do before(:each) do @double_registry.should_receive(:key_exists?).twice.with(testkey1).and_return(false) end it "should create the key and the value" do @double_registry.should_receive(:create_key).with(testkey1, false) @double_registry.should_receive(:set_value).with(testkey1, testval1) @provider.load_current_resource @provider.action_create end end context "when the key does not exist and the values in the new resource are empty" do it "should create the key" do @new_resource.values([]) @double_registry.should_receive(:key_exists?).twice.with(testkey1).and_return(false) @double_registry.should_receive(:create_key).with(testkey1, false) @double_registry.should_not_receive(:set_value) @provider.load_current_resource @provider.action_create end end end describe "action_create_if_missing" do context "when the key exists" do before(:each) do @double_registry.should_receive(:key_exists?).twice.with(testkey1).and_return(true) end it "should do nothing if the key and the value both exist" do @double_registry.should_receive(:get_values).with(testkey1).and_return( testval1 ) @double_registry.should_not_receive(:set_value) @provider.load_current_resource @provider.action_create_if_missing end it "should create the value if the key exists but the value does not" do @double_registry.should_receive(:get_values).with(testkey1).and_return( testval2 ) @double_registry.should_receive(:set_value).with(testkey1, testval1) @provider.load_current_resource @provider.action_create_if_missing end it "should not set the value if the key exists but the data does not match" do @double_registry.should_receive(:get_values).with(testkey1).and_return( testval1_wrong_data ) @double_registry.should_not_receive(:set_value) @provider.load_current_resource @provider.action_create_if_missing end it "should not set the value if the key exists but the type does not match" do @double_registry.should_receive(:get_values).with(testkey1).and_return( testval1_wrong_type ) @double_registry.should_not_receive(:set_value) @provider.load_current_resource @provider.action_create_if_missing end end context "when the key does not exist" do before(:each) do @double_registry.should_receive(:key_exists?).twice.with(testkey1).and_return(false) end it "should create the key and the value" do @double_registry.should_receive(:create_key).with(testkey1, false) @double_registry.should_receive(:set_value).with(testkey1, testval1) @provider.load_current_resource @provider.action_create_if_missing end end end describe "action_delete" do context "when the key exists" do before(:each) do @double_registry.should_receive(:key_exists?).twice.with(testkey1).and_return(true) end it "deletes the value when the value exists" do @double_registry.should_receive(:get_values).with(testkey1).and_return( testval1 ) @double_registry.should_receive(:delete_value).with(testkey1, testval1) @provider.load_current_resource @provider.action_delete end it "deletes the value when the value exists, but the type is wrong" do @double_registry.should_receive(:get_values).with(testkey1).and_return( testval1_wrong_type ) @double_registry.should_receive(:delete_value).with(testkey1, testval1) @provider.load_current_resource @provider.action_delete end it "deletes the value when the value exists, but the data is wrong" do @double_registry.should_receive(:get_values).with(testkey1).and_return( testval1_wrong_data ) @double_registry.should_receive(:delete_value).with(testkey1, testval1) @provider.load_current_resource @provider.action_delete end it "does not delete the value when the value does not exist" do @double_registry.should_receive(:get_values).with(testkey1).and_return( testval2 ) @double_registry.should_not_receive(:delete_value) @provider.load_current_resource @provider.action_delete end end context "when the key does not exist" do before(:each) do @double_registry.should_receive(:key_exists?).twice.with(testkey1).and_return(false) end it "does nothing" do @double_registry.should_not_receive(:delete_value) @provider.load_current_resource @provider.action_delete end end end describe "action_delete_key" do context "when the key exists" do before(:each) do @double_registry.should_receive(:key_exists?).twice.with(testkey1).and_return(true) end it "deletes the key" do @double_registry.should_receive(:get_values).with(testkey1).and_return( testval1 ) @double_registry.should_receive(:delete_key).with(testkey1, false) @provider.load_current_resource @provider.action_delete_key end end context "when the key does not exist" do before(:each) do @double_registry.should_receive(:key_exists?).twice.with(testkey1).and_return(false) end it "does nothing" do @double_registry.should_not_receive(:delete_key) @provider.load_current_resource @provider.action_delete_key end end end end chef-11.8.2/spec/unit/provider/package/0000755000004100000410000000000012254362222017676 5ustar www-datawww-datachef-11.8.2/spec/unit/provider/package/aix_spec.rb0000644000004100000410000001571312254362222022025 0ustar www-datawww-data# # Author:: Deepali Jagtap (deepali.jagtap@clogeny.com) # Author:: Prabhu Das (prabhu.das@clogeny.com) # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Package::Aix do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Package.new("samba.base") @new_resource.source("/tmp/samba.base") @provider = Chef::Provider::Package::Aix.new(@new_resource, @run_context) ::File.stub!(:exists?).and_return(true) end describe "assessing the current package status" do before do @bffinfo ="/usr/lib/objrepos:samba.base:3.3.12.0::COMMITTED:I:Samba for AIX: /etc/objrepos:samba.base:3.3.12.0::COMMITTED:I:Samba for AIX:" @status = mock("Status", :exitstatus => 0) end it "should create a current resource with the name of new_resource" do @provider.stub!(:popen4).and_return(@status) @provider.load_current_resource @provider.current_resource.name.should == "samba.base" end it "should set the current resource bff package name to the new resource bff package name" do @provider.stub!(:popen4).and_return(@status) @provider.load_current_resource @provider.current_resource.package_name.should == "samba.base" end it "should raise an exception if a source is supplied but not found" do @provider.stub!(:popen4).and_return(@status) ::File.stub!(:exists?).and_return(false) @provider.define_resource_requirements @provider.load_current_resource lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Package) end it "should get the source package version from lslpp if provided" do @stdout = StringIO.new(@bffinfo) @stdin, @stderr = StringIO.new, StringIO.new @provider.should_receive(:popen4).with("installp -L -d /tmp/samba.base").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.should_receive(:popen4).with("lslpp -lcq samba.base").and_return(@status) @provider.load_current_resource @provider.current_resource.package_name.should == "samba.base" @new_resource.version.should == "3.3.12.0" end it "should return the current version installed if found by lslpp" do @stdout = StringIO.new(@bffinfo) @stdin, @stderr = StringIO.new, StringIO.new @provider.should_receive(:popen4).with("installp -L -d /tmp/samba.base").and_return(@status) @provider.should_receive(:popen4).with("lslpp -lcq samba.base").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.load_current_resource @provider.current_resource.version.should == "3.3.12.0" end it "should raise an exception if the source is not set but we are installing" do @new_resource = Chef::Resource::Package.new("samba.base") @provider = Chef::Provider::Package::Aix.new(@new_resource, @run_context) @provider.stub!(:popen4).and_return(@status) lambda { @provider.run_action(:install) }.should raise_error(Chef::Exceptions::Package) end it "should raise an exception if installp/lslpp fails to run" do @status = mock("Status", :exitstatus => -1) @provider.stub!(:popen4).and_return(@status) lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package) end it "should return a current resource with a nil version if the package is not found" do @stdout = StringIO.new @provider.should_receive(:popen4).with("installp -L -d /tmp/samba.base").and_return(@status) @provider.should_receive(:popen4).with("lslpp -lcq samba.base").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.load_current_resource @provider.current_resource.version.should be_nil end end describe "candidate_version" do it "should return the candidate_version variable if already setup" do @provider.candidate_version = "3.3.12.0" @provider.should_not_receive(:popen4) @provider.candidate_version end it "should lookup the candidate_version if the variable is not already set" do @status = mock("Status", :exitstatus => 0) @provider.should_receive(:popen4).and_return(@status) @provider.candidate_version end it "should throw and exception if the exitstatus is not 0" do @status = mock("Status", :exitstatus => 1) @provider.stub!(:popen4).and_return(@status) lambda { @provider.candidate_version }.should raise_error(Chef::Exceptions::Package) end end describe "install and upgrade" do it "should run installp -aYF -d with the package source to install" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "installp -aYF -d /tmp/samba.base samba.base" }) @provider.install_package("samba.base", "3.3.12.0") end it "should run when the package is a path to install" do @new_resource = Chef::Resource::Package.new("/tmp/samba.base") @provider = Chef::Provider::Package::Aix.new(@new_resource, @run_context) @new_resource.source.should == "/tmp/samba.base" @provider.should_receive(:run_command_with_systems_locale).with({ :command => "installp -aYF -d /tmp/samba.base /tmp/samba.base" }) @provider.install_package("/tmp/samba.base", "3.3.12.0") end it "should run installp with -eLogfile option." do @new_resource.stub!(:options).and_return("-e/tmp/installp.log") @provider.should_receive(:run_command_with_systems_locale).with({ :command => "installp -aYF -e/tmp/installp.log -d /tmp/samba.base samba.base" }) @provider.install_package("samba.base", "3.3.12.0") end end describe "remove" do it "should run installp -u samba.base to remove the package" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "installp -u samba.base" }) @provider.remove_package("samba.base", "3.3.12.0") end it "should run installp -u -e/tmp/installp.log with options -e/tmp/installp.log" do @new_resource.stub!(:options).and_return("-e/tmp/installp.log") @provider.should_receive(:run_command_with_systems_locale).with({ :command => "installp -u -e/tmp/installp.log samba.base" }) @provider.remove_package("samba.base", "3.3.12.0") end end end chef-11.8.2/spec/unit/provider/package/portage_spec.rb0000644000004100000410000003376112254362222022710 0ustar www-datawww-data# # Author:: Caleb Tennis () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Package::Portage, "load_current_resource" do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Package.new("dev-util/git") @new_resource_without_category = Chef::Resource::Package.new("git") @current_resource = Chef::Resource::Package.new("dev-util/git") @provider = Chef::Provider::Package::Portage.new(@new_resource, @run_context) Chef::Resource::Package.stub!(:new).and_return(@current_resource) end describe "when determining the current state of the package" do it "should create a current resource with the name of new_resource" do ::Dir.stub!(:[]).with("/var/db/pkg/dev-util/git-*").and_return(["/var/db/pkg/dev-util/git-1.0.0"]) Chef::Resource::Package.should_receive(:new).and_return(@current_resource) @provider.load_current_resource end it "should set the current resource package name to the new resource package name" do ::Dir.stub!(:[]).with("/var/db/pkg/dev-util/git-*").and_return(["/var/db/pkg/dev-util/git-1.0.0"]) @current_resource.should_receive(:package_name).with(@new_resource.package_name) @provider.load_current_resource end it "should return a current resource with the correct version if the package is found" do ::Dir.stub!(:[]).with("/var/db/pkg/dev-util/git-*").and_return(["/var/db/pkg/dev-util/git-foobar-0.9", "/var/db/pkg/dev-util/git-1.0.0"]) @provider.load_current_resource @provider.current_resource.version.should == "1.0.0" end it "should return a current resource with the correct version if the package is found with revision" do ::Dir.stub!(:[]).with("/var/db/pkg/dev-util/git-*").and_return(["/var/db/pkg/dev-util/git-1.0.0-r1"]) @provider.load_current_resource @provider.current_resource.version.should == "1.0.0-r1" end it "should return a current resource with a nil version if the package is not found" do ::Dir.stub!(:[]).with("/var/db/pkg/dev-util/git-*").and_return(["/var/db/pkg/dev-util/notgit-1.0.0"]) @provider.load_current_resource @provider.current_resource.version.should be_nil end it "should return a package name match from /var/db/pkg/* if a category isn't specified and a match is found" do ::Dir.stub!(:[]).with("/var/db/pkg/*/git-*").and_return(["/var/db/pkg/dev-util/git-foobar-0.9", "/var/db/pkg/dev-util/git-1.0.0"]) @provider = Chef::Provider::Package::Portage.new(@new_resource_without_category, @run_context) @provider.load_current_resource @provider.current_resource.version.should == "1.0.0" end it "should return a current resource with a nil version if a category isn't specified and a name match from /var/db/pkg/* is not found" do ::Dir.stub!(:[]).with("/var/db/pkg/*/git-*").and_return(["/var/db/pkg/dev-util/notgit-1.0.0"]) @provider = Chef::Provider::Package::Portage.new(@new_resource_without_category, @run_context) @provider.load_current_resource @provider.current_resource.version.should be_nil end it "should throw an exception if a category isn't specified and multiple packages are found" do ::Dir.stub!(:[]).with("/var/db/pkg/*/git-*").and_return(["/var/db/pkg/dev-util/git-1.0.0", "/var/db/pkg/funny-words/git-1.0.0"]) @provider = Chef::Provider::Package::Portage.new(@new_resource_without_category, @run_context) lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package) end it "should return a current resource with a nil version if a category is specified and multiple packages are found" do ::Dir.stub!(:[]).with("/var/db/pkg/dev-util/git-*").and_return(["/var/db/pkg/dev-util/git-1.0.0", "/var/db/pkg/funny-words/git-1.0.0"]) @provider = Chef::Provider::Package::Portage.new(@new_resource, @run_context) @provider.load_current_resource @provider.current_resource.version.should be_nil end it "should return a current resource with a nil version if a category is not specified and multiple packages from the same category are found" do ::Dir.stub!(:[]).with("/var/db/pkg/*/git-*").and_return(["/var/db/pkg/dev-util/git-1.0.0", "/var/db/pkg/dev-util/git-1.0.1"]) @provider = Chef::Provider::Package::Portage.new(@new_resource_without_category, @run_context) @provider.load_current_resource @provider.current_resource.version.should be_nil end end describe "once the state of the package is known" do describe Chef::Provider::Package::Portage, "candidate_version" do it "should return the candidate_version variable if already set" do @provider.candidate_version = "1.0.0" @provider.should_not_receive(:popen4) @provider.candidate_version end it "should throw an exception if the exitstatus is not 0" do @status = mock("Status", :exitstatus => 1) @provider.stub!(:popen4).and_return(@status) lambda { @provider.candidate_version }.should raise_error(Chef::Exceptions::Package) end it "should find the candidate_version if a category is specifed and there are no duplicates" do output = < 0) @provider.should_receive(:popen4).and_yield(nil, nil, StringIO.new(output), nil).and_return(@status) @provider.candidate_version.should == "1.6.0.6" end it "should find the candidate_version if a category is not specifed and there are no duplicates" do output = < 0) @provider = Chef::Provider::Package::Portage.new(@new_resource_without_category, @run_context) @provider.should_receive(:popen4).and_yield(nil, nil, StringIO.new(output), nil).and_return(@status) @provider.candidate_version.should == "1.6.0.6" end it "should throw an exception if a category is not specified and there are duplicates" do output = < 0) @provider = Chef::Provider::Package::Portage.new(@new_resource_without_category, @run_context) @provider.should_receive(:popen4).and_yield(nil, nil, StringIO.new(output), nil).and_return(@status) lambda { @provider.candidate_version }.should raise_error(Chef::Exceptions::Package) end it "should find the candidate_version if a category is specifed and there are category duplicates" do output = < 0) @provider = Chef::Provider::Package::Portage.new(@new_resource, @run_context) @provider.should_receive(:popen4).and_yield(nil, nil, StringIO.new(output), nil).and_return(@status) @provider.candidate_version.should == "1.6.0.6" end end describe Chef::Provider::Package::Portage, "install_package" do it "should install a normally versioned package using portage" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "emerge -g --color n --nospinner --quiet =dev-util/git-1.0.0" }) @provider.install_package("dev-util/git", "1.0.0") end it "should install a tilde versioned package using portage" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "emerge -g --color n --nospinner --quiet ~dev-util/git-1.0.0" }) @provider.install_package("dev-util/git", "~1.0.0") end it "should add options to the emerge command when specified" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "emerge -g --color n --nospinner --quiet --oneshot =dev-util/git-1.0.0" }) @new_resource.stub!(:options).and_return("--oneshot") @provider.install_package("dev-util/git", "1.0.0") end end describe Chef::Provider::Package::Portage, "remove_package" do it "should un-emerge the package with no version specified" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "emerge --unmerge --color n --nospinner --quiet dev-util/git" }) @provider.remove_package("dev-util/git", nil) end it "should un-emerge the package with a version specified" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "emerge --unmerge --color n --nospinner --quiet =dev-util/git-1.0.0" }) @provider.remove_package("dev-util/git", "1.0.0") end end end end chef-11.8.2/spec/unit/provider/package/freebsd_spec.rb0000644000004100000410000003354212254362222022656 0ustar www-datawww-data# # Authors:: Bryan McLellan (btm@loftninjas.org) # Matthew Landauer (matthew@openaustralia.org) # Copyright:: Copyright (c) 2009 Bryan McLellan, Matthew Landauer # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'ostruct' describe Chef::Provider::Package::Freebsd, "load_current_resource" do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Package.new("zsh") @current_resource = Chef::Resource::Package.new("zsh") @provider = Chef::Provider::Package::Freebsd.new(@new_resource, @run_context) @provider.current_resource = @current_resource ::File.stub!(:exist?).with('/usr/ports/Makefile').and_return(false) end describe "when determining the current package state" do before do @provider.stub!(:ports_candidate_version).and_return("4.3.6") end it "should create a current resource with the name of the new_resource" do current_resource = Chef::Provider::Package::Freebsd.new(@new_resource, @run_context).current_resource current_resource.name.should == "zsh" end it "should return a version if the package is installed" do @provider.should_receive(:current_installed_version).and_return("4.3.6_7") @provider.load_current_resource @current_resource.version.should == "4.3.6_7" end it "should return nil if the package is not installed" do @provider.should_receive(:current_installed_version).and_return(nil) @provider.load_current_resource @current_resource.version.should be_nil end it "should return a candidate version if it exists" do @provider.should_receive(:current_installed_version).and_return(nil) @provider.load_current_resource @provider.candidate_version.should eql("4.3.6") end end describe "when querying for package state and attributes" do before do #@new_resource = Chef::Resource::Package.new("zsh") #@provider = Chef::Provider::Package::Freebsd.new(@node, @new_resource) #@status = mock("Status", :exitstatus => 0) #@stdin = mock("STDIN", :null_object => true) #@stdout = mock("STDOUT", :null_object => true) #@stderr = mock("STDERR", :null_object => true) #@pid = mock("PID", :null_object => true) end it "should return the version number when it is installed" do pkg_info = OpenStruct.new(:stdout => "zsh-4.3.6_7") @provider.should_receive(:shell_out!).with('pkg_info -E "zsh*"', :env => nil, :returns => [0,1]).and_return(pkg_info) #@provider.should_receive(:popen4).with('pkg_info -E "zsh*"').and_yield(@pid, @stdin, ["zsh-4.3.6_7"], @stderr).and_return(@status) @provider.stub!(:package_name).and_return("zsh") @provider.current_installed_version.should == "4.3.6_7" end it "does not set the current version number when the package is not installed" do pkg_info = OpenStruct.new(:stdout => "") @provider.should_receive(:shell_out!).with('pkg_info -E "zsh*"', :env => nil, :returns => [0,1]).and_return(pkg_info) @provider.stub!(:package_name).and_return("zsh") @provider.current_installed_version.should be_nil end it "should return the port path for a valid port name" do whereis = OpenStruct.new(:stdout => "zsh: /usr/ports/shells/zsh") @provider.should_receive(:shell_out!).with("whereis -s zsh", :env => nil).and_return(whereis) #@provider.should_receive(:popen4).with("whereis -s zsh").and_yield(@pid, @stdin, ["zsh: /usr/ports/shells/zsh"], @stderr).and_return(@status) @provider.stub!(:port_name).and_return("zsh") @provider.port_path.should == "/usr/ports/shells/zsh" end # Not happy with the form of these tests as they are far too closely tied to the implementation and so very fragile. it "should return the ports candidate version when given a valid port path" do @provider.stub!(:port_path).and_return("/usr/ports/shells/zsh") make_v = OpenStruct.new(:stdout => "4.3.6\n") @provider.should_receive(:shell_out!).with("make -V PORTVERSION", {:cwd=>"/usr/ports/shells/zsh", :returns=>[0, 1], :env=>nil}).and_return(make_v) @provider.ports_candidate_version.should == "4.3.6" end it "should figure out the package name when we have ports" do ::File.stub!(:exist?).with('/usr/ports/Makefile').and_return(true) @provider.stub!(:port_path).and_return("/usr/ports/shells/zsh") make_v = OpenStruct.new(:stdout => "zsh-4.3.6_7\n") @provider.should_receive(:shell_out!).with("make -V PKGNAME", {:cwd=>"/usr/ports/shells/zsh", :env=>nil, :returns=>[0, 1]}).and_return(make_v) #@provider.should_receive(:ports_makefile_variable_value).with("PKGNAME").and_return("zsh-4.3.6_7") @provider.package_name.should == "zsh" end end describe Chef::Provider::Package::Freebsd, "install_package" do before(:each) do @cmd_result = OpenStruct.new(:status => true) @provider.current_resource = @current_resource @provider.stub!(:package_name).and_return("zsh") @provider.stub!(:latest_link_name).and_return("zsh") @provider.stub!(:port_path).and_return("/usr/ports/shells/zsh") end it "should run pkg_add -r with the package name" do @provider.should_receive(:shell_out!).with("pkg_add -r zsh", :env => nil).and_return(@cmd_result) @provider.install_package("zsh", "4.3.6_7") end it "should run make install when installing from ports" do @new_resource.stub!(:source).and_return("ports") @provider.should_not_receive(:shell_out!).with("make -DBATCH -f /usr/ports/shells/zsh/Makefile install", :timeout => 1200, :env=>nil) @provider.should_receive(:shell_out!).with("make -DBATCH install", :timeout => 1200, :env=>nil, :cwd => @provider.port_path).and_return(@cmd_result) @provider.install_package("zsh", "4.3.6_7") end end describe Chef::Provider::Package::Freebsd, "port path" do before do #@node = Chef::Node.new @new_resource = Chef::Resource::Package.new("zsh") @new_resource.cookbook_name = "adventureclub" @provider = Chef::Provider::Package::Freebsd.new(@new_resource, @run_context) end it "should figure out the port path from the package_name using whereis" do whereis = OpenStruct.new(:stdout => "zsh: /usr/ports/shells/zsh") @provider.should_receive(:shell_out!).with("whereis -s zsh", :env=>nil).and_return(whereis) @provider.port_path.should == "/usr/ports/shells/zsh" end it "should use the package_name as the port path when it starts with /" do new_resource = Chef::Resource::Package.new("/usr/ports/www/wordpress") provider = Chef::Provider::Package::Freebsd.new(new_resource, @run_context) provider.should_not_receive(:popen4) provider.port_path.should == "/usr/ports/www/wordpress" end it "should use the package_name as a relative path from /usr/ports when it contains / but doesn't start with it" do # @new_resource = mock( "Chef::Resource::Package", # :package_name => "www/wordpress", # :cookbook_name => "xenoparadox") new_resource = Chef::Resource::Package.new("www/wordpress") provider = Chef::Provider::Package::Freebsd.new(new_resource, @run_context) provider.should_not_receive(:popen4) provider.port_path.should == "/usr/ports/www/wordpress" end end describe Chef::Provider::Package::Freebsd, "ruby-iconv (package with a dash in the name)" do before(:each) do @new_resource = Chef::Resource::Package.new("ruby-iconv") @current_resource = Chef::Resource::Package.new("ruby-iconv") @provider = Chef::Provider::Package::Freebsd.new(@new_resource, @run_context) @provider.current_resource = @current_resource @provider.stub!(:port_path).and_return("/usr/ports/converters/ruby-iconv") @provider.stub!(:package_name).and_return("ruby18-iconv") @provider.stub!(:latest_link_name).and_return("ruby18-iconv") @install_result = OpenStruct.new(:status => true) end it "should run pkg_add -r with the package name" do @provider.should_receive(:shell_out!).with("pkg_add -r ruby18-iconv", :env => nil).and_return(@install_result) @provider.install_package("ruby-iconv", "1.0") end it "should run make install when installing from ports" do @new_resource.stub!(:source).and_return("ports") @provider.should_receive(:shell_out!).with("make -DBATCH install", :timeout => 1200, :env=>nil, :cwd => @provider.port_path).and_return(@install_result) @provider.install_package("ruby-iconv", "1.0") end end describe Chef::Provider::Package::Freebsd, "remove_package" do before(:each) do @pkg_delete = OpenStruct.new(:status => true) @new_resource.version "4.3.6_7" @current_resource.version "4.3.6_7" @provider.current_resource = @current_resource @provider.stub!(:package_name).and_return("zsh") end it "should run pkg_delete with the package name and version" do @provider.should_receive(:shell_out!).with("pkg_delete zsh-4.3.6_7", :env => nil).and_return(@pkg_delete) @provider.remove_package("zsh", "4.3.6_7") end end # CHEF-4371 # There are some port names that contain special characters such as +'s. This breaks the regular expression used to determine what # version of a package is currently installed and to get the port_path. # Example package name: bonnie++ describe Chef::Provider::Package::Freebsd, "bonnie++ (package with a plus in the name :: CHEF-4371)" do before(:each) do @new_resource = Chef::Resource::Package.new("bonnie++") @current_resource = Chef::Resource::Package.new("bonnie++") @provider = Chef::Provider::Package::Freebsd.new(@new_resource, @run_context) @provider.current_resource = @current_resource end it "should return the port path for a valid port name" do whereis = OpenStruct.new(:stdout => "bonnie++: /usr/ports/benchmarks/bonnie++") @provider.should_receive(:shell_out!).with("whereis -s bonnie++", :env => nil).and_return(whereis) @provider.stub!(:port_name).and_return("bonnie++") @provider.port_path.should == "/usr/ports/benchmarks/bonnie++" end it "should return the version number when it is installed" do pkg_info = OpenStruct.new(:stdout => "bonnie++-1.96") @provider.should_receive(:shell_out!).with('pkg_info -E "bonnie++*"', :env => nil, :returns => [0,1]).and_return(pkg_info) @provider.stub!(:package_name).and_return("bonnie++") @provider.current_installed_version.should == "1.96" end end # A couple of examples to show up the difficulty of determining the command to install the binary package given the port: # PORT DIRECTORY INSTALLED PACKAGE NAME COMMAND TO INSTALL PACKAGE # /usr/ports/lang/perl5.8 perl-5.8.8_1 pkg_add -r perl # /usr/ports/databases/mysql50-server mysql-server-5.0.45_1 pkg_add -r mysql50-server # # So, in one case it appears the command to install the package can be derived from the name of the port directory and in the # other case it appears the command can be derived from the package name. Very confusing! # Well, luckily, after much poking around, I discovered that the two can be disambiguated through the use of the LATEST_LINK # variable which is set by the ports Makefile # # PORT DIRECTORY LATEST_LINK INSTALLED PACKAGE NAME COMMAND TO INSTALL PACKAGE # /usr/ports/lang/perl5.8 perl perl-5.8.8_1 pkg_add -r perl # /usr/ports/databases/mysql50-server mysql50-server mysql-server-5.0.45_1 pkg_add -r mysql50-server # # The variable LATEST_LINK is named that way because the directory that "pkg_add -r" downloads from is called "Latest" and # contains the "latest" versions of package as symbolic links to the files in the "All" directory. describe Chef::Provider::Package::Freebsd, "install_package latest link fixes" do it "should install the perl binary package with the correct name" do @new_resource = Chef::Resource::Package.new("perl5.8") @current_resource = Chef::Resource::Package.new("perl5.8") @provider = Chef::Provider::Package::Freebsd.new(@new_resource, @run_context) @provider.current_resource = @current_resource @provider.stub!(:package_name).and_return("perl") @provider.stub!(:latest_link_name).and_return("perl") cmd = OpenStruct.new(:status => true) @provider.should_receive(:shell_out!).with("pkg_add -r perl", :env => nil).and_return(cmd) @provider.install_package("perl5.8", "5.8.8_1") end it "should install the mysql50-server binary package with the correct name" do @new_resource = Chef::Resource::Package.new("mysql50-server") @current_resource = Chef::Resource::Package.new("mysql50-server") @provider = Chef::Provider::Package::Freebsd.new(@new_resource, @run_context) @provider.current_resource = @current_resource @provider.stub!(:package_name).and_return("mysql-server") @provider.stub!(:latest_link_name).and_return("mysql50-server") cmd = OpenStruct.new(:status => true) @provider.should_receive(:shell_out!).with("pkg_add -r mysql50-server", :env=>nil).and_return(cmd) @provider.install_package("mysql50-server", "5.0.45_1") end end end chef-11.8.2/spec/unit/provider/package/yum_spec.rb0000644000004100000410000021412512254362222022054 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Package::Yum do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Package.new('cups') @status = mock("Status", :exitstatus => 0) @yum_cache = mock( 'Chef::Provider::Yum::YumCache', :reload_installed => true, :reset => true, :installed_version => "1.2.4-11.18.el5", :candidate_version => "1.2.4-11.18.el5_2.3", :package_available? => true, :version_available? => true, :allow_multi_install => [ "kernel" ], :package_repository => "base", :disable_extra_repo_control => true ) Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) @pid = mock("PID") end describe "when loading the current system state" do it "should create a current resource with the name of the new_resource" do @provider.load_current_resource @provider.current_resource.name.should == "cups" end it "should set the current resources package name to the new resources package name" do @provider.load_current_resource @provider.current_resource.package_name.should == "cups" end it "should set the installed version to nil on the current resource if no installed package" do @yum_cache.stub!(:installed_version).and_return(nil) @provider.load_current_resource @provider.current_resource.version.should be_nil end it "should set the installed version if yum has one" do @provider.load_current_resource @provider.current_resource.version.should == "1.2.4-11.18.el5" end it "should set the candidate version if yum info has one" do @provider.load_current_resource @provider.candidate_version.should eql("1.2.4-11.18.el5_2.3") end it "should return the current resouce" do @provider.load_current_resource.should eql(@provider.current_resource) end describe "when arch in package_name" do it "should set the arch if no existing package_name is found and new_package_name+new_arch is available" do @new_resource = Chef::Resource::YumPackage.new('testing.noarch') @yum_cache = mock( 'Chef::Provider::Yum::YumCache' ) @yum_cache.stub!(:installed_version) do |package_name, arch| # nothing installed for package_name/new_package_name nil end @yum_cache.stub!(:candidate_version) do |package_name, arch| if package_name == "testing.noarch" || package_name == "testing.more.noarch" nil # candidate for new_package_name elsif package_name == "testing" || package_name == "testing.more" "1.1" end end @yum_cache.stub!(:package_available?).and_return(true) @yum_cache.stub!(:disable_extra_repo_control).and_return(true) Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) @provider.load_current_resource @provider.new_resource.package_name.should == "testing" @provider.new_resource.arch.should == "noarch" @provider.arch.should == "noarch" @new_resource = Chef::Resource::YumPackage.new('testing.more.noarch') @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) @provider.load_current_resource @provider.new_resource.package_name.should == "testing.more" @provider.new_resource.arch.should == "noarch" @provider.arch.should == "noarch" end it "should not set the arch when an existing package_name is found" do @new_resource = Chef::Resource::YumPackage.new('testing.beta3') @yum_cache = mock( 'Chef::Provider::Yum::YumCache' ) @yum_cache.stub!(:installed_version) do |package_name, arch| # installed for package_name if package_name == "testing.beta3" || package_name == "testing.beta3.more" "1.1" elsif package_name == "testing" || package_name == "testing.beta3" nil end end @yum_cache.stub!(:candidate_version) do |package_name, arch| # no candidate for package_name/new_package_name nil end @yum_cache.stub!(:package_available?).and_return(true) @yum_cache.stub!(:disable_extra_repo_control).and_return(true) Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) # annoying side effect of the fun stub'ing above @provider.load_current_resource @provider.new_resource.package_name.should == "testing.beta3" @provider.new_resource.arch.should == nil @provider.arch.should == nil @new_resource = Chef::Resource::YumPackage.new('testing.beta3.more') @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) @provider.load_current_resource @provider.new_resource.package_name.should == "testing.beta3.more" @provider.new_resource.arch.should == nil @provider.arch.should == nil end it "should not set the arch when no existing package_name or new_package_name+new_arch is found" do @new_resource = Chef::Resource::YumPackage.new('testing.beta3') @yum_cache = mock( 'Chef::Provider::Yum::YumCache' ) @yum_cache.stub!(:installed_version) do |package_name, arch| # nothing installed for package_name/new_package_name nil end @yum_cache.stub!(:candidate_version) do |package_name, arch| # no candidate for package_name/new_package_name nil end @yum_cache.stub!(:package_available?).and_return(true) @yum_cache.stub!(:disable_extra_repo_control).and_return(true) Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) @provider.load_current_resource @provider.new_resource.package_name.should == "testing.beta3" @provider.new_resource.arch.should == nil @provider.arch.should == nil @new_resource = Chef::Resource::YumPackage.new('testing.beta3.more') @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) @provider.load_current_resource @provider.new_resource.package_name.should == "testing.beta3.more" @provider.new_resource.arch.should == nil @provider.arch.should == nil end it "should ensure it doesn't clobber an existing arch if passed" do @new_resource = Chef::Resource::YumPackage.new('testing.i386') @new_resource.arch("x86_64") @yum_cache = mock( 'Chef::Provider::Yum::YumCache' ) @yum_cache.stub!(:installed_version) do |package_name, arch| # nothing installed for package_name/new_package_name nil end @yum_cache.stub!(:candidate_version) do |package_name, arch| if package_name == "testing.noarch" nil # candidate for new_package_name elsif package_name == "testing" "1.1" end end.and_return("something") @yum_cache.stub!(:package_available?).and_return(true) @yum_cache.stub!(:disable_extra_repo_control).and_return(true) Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) @provider.load_current_resource @provider.new_resource.package_name.should == "testing.i386" @provider.new_resource.arch.should == "x86_64" end end it "should flush the cache if :before is true" do @new_resource.stub!(:flush_cache).and_return({:after => false, :before => true}) @yum_cache.should_receive(:reload).once @provider.load_current_resource end it "should flush the cache if :before is false" do @new_resource.stub!(:flush_cache).and_return({:after => false, :before => false}) @yum_cache.should_not_receive(:reload) @provider.load_current_resource end it "should detect --enablerepo or --disablerepo when passed among options, collect them preserving order and notify the yum cache" do @new_resource.stub!(:options).and_return("--stuff --enablerepo=foo --otherthings --disablerepo=a,b,c --enablerepo=bar") @yum_cache.should_receive(:enable_extra_repo_control).with("--enablerepo=foo --disablerepo=a,b,c --enablerepo=bar") @provider.load_current_resource end it "should let the yum cache know extra repos are disabled if --enablerepo or --disablerepo aren't among options" do @new_resource.stub!(:options).and_return("--stuff --otherthings") @yum_cache.should_receive(:disable_extra_repo_control) @provider.load_current_resource end it "should let the yum cache know extra repos are disabled if options aren't set" do @new_resource.stub!(:options).and_return(nil) @yum_cache.should_receive(:disable_extra_repo_control) @provider.load_current_resource end it "should search provides if package name can't be found then set package_name to match" do @yum_cache = mock( 'Chef::Provider::Yum::YumCache', :reload_installed => true, :reset => true, :installed_version => "1.2.4-11.18.el5", :candidate_version => "1.2.4-11.18.el5", :package_available? => false, :version_available? => true, :disable_extra_repo_control => true ) Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) pkg = Chef::Provider::Package::Yum::RPMPackage.new("test-package", "1.2.4-11.18.el5", "x86_64", []) @yum_cache.should_receive(:packages_from_require).and_return([pkg]) @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) @provider.load_current_resource @new_resource.package_name.should == "test-package" end it "should search provides if package name can't be found, warn about multiple matches, but use the first one" do @yum_cache = mock( 'Chef::Provider::Yum::YumCache', :reload_installed => true, :reset => true, :installed_version => "1.2.4-11.18.el5", :candidate_version => "1.2.4-11.18.el5", :package_available? => false, :version_available? => true, :disable_extra_repo_control => true ) Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) pkg_x = Chef::Provider::Package::Yum::RPMPackage.new("test-package-x", "1.2.4-11.18.el5", "x86_64", []) pkg_y = Chef::Provider::Package::Yum::RPMPackage.new("test-package-y", "1.2.6-11.3.el5", "i386", []) @yum_cache.should_receive(:packages_from_require).and_return([pkg_x, pkg_y]) Chef::Log.should_receive(:warn).exactly(1).times.with(%r{matched multiple Provides}) @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) @provider.load_current_resource @new_resource.package_name.should == "test-package-x" end it "should search provides if no package is available - if no match in installed provides then load the complete set" do @yum_cache = mock( 'Chef::Provider::Yum::YumCache', :reload_installed => true, :reset => true, :installed_version => "1.2.4-11.18.el5", :candidate_version => "1.2.4-11.18.el5", :package_available? => false, :version_available? => true, :disable_extra_repo_control => true ) Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) @yum_cache.should_receive(:packages_from_require).twice.and_return([]) @yum_cache.should_receive(:reload_provides) @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) @provider.load_current_resource end it "should search provides if no package is available and not load the complete set if action is :remove or :purge" do @yum_cache = mock( 'Chef::Provider::Yum::YumCache', :reload_installed => true, :reset => true, :installed_version => "1.2.4-11.18.el5", :candidate_version => "1.2.4-11.18.el5", :package_available? => false, :version_available? => true, :disable_extra_repo_control => true ) Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) @yum_cache.should_receive(:packages_from_require).once.and_return([]) @yum_cache.should_not_receive(:reload_provides) @new_resource.action(:remove) @provider.load_current_resource @yum_cache.should_receive(:packages_from_require).once.and_return([]) @yum_cache.should_not_receive(:reload_provides) @new_resource.action(:purge) @provider.load_current_resource end it "should search provides if no package is available - if no match in provides leave the name intact" do @yum_cache = mock( 'Chef::Provider::Yum::YumCache', :reload_provides => true, :reload_installed => true, :reset => true, :installed_version => "1.2.4-11.18.el5", :candidate_version => "1.2.4-11.18.el5", :package_available? => false, :version_available? => true, :disable_extra_repo_control => true ) Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) @yum_cache.should_receive(:packages_from_require).twice.and_return([]) @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) @provider.load_current_resource @new_resource.package_name.should == "cups" end end describe "when installing a package" do it "should run yum install with the package name and version" do @provider.load_current_resource Chef::Provider::Package::Yum::RPMUtils.stub!(:rpmvercmp).and_return(-1) @provider.should_receive(:yum_command).with( "yum -d0 -e0 -y install emacs-1.0" ) @provider.install_package("emacs", "1.0") end it "should run yum localinstall if given a path to an rpm" do @new_resource.stub!(:source).and_return("/tmp/emacs-21.4-20.el5.i386.rpm") @provider.should_receive(:yum_command).with( "yum -d0 -e0 -y localinstall /tmp/emacs-21.4-20.el5.i386.rpm" ) @provider.install_package("emacs", "21.4-20.el5") end it "should run yum localinstall if given a path to an rpm as the package" do @new_resource = Chef::Resource::Package.new("/tmp/emacs-21.4-20.el5.i386.rpm") ::File.stub!(:exists?).and_return(true) @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) @new_resource.source.should == "/tmp/emacs-21.4-20.el5.i386.rpm" @provider.should_receive(:yum_command).with( "yum -d0 -e0 -y localinstall /tmp/emacs-21.4-20.el5.i386.rpm" ) @provider.install_package("/tmp/emacs-21.4-20.el5.i386.rpm", "21.4-20.el5") end it "should run yum install with the package name, version and arch" do @provider.load_current_resource @new_resource.stub!(:arch).and_return("i386") Chef::Provider::Package::Yum::RPMUtils.stub!(:rpmvercmp).and_return(-1) @provider.should_receive(:yum_command).with( "yum -d0 -e0 -y install emacs-21.4-20.el5.i386" ) @provider.install_package("emacs", "21.4-20.el5") end it "installs the package with the options given in the resource" do @provider.load_current_resource @provider.candidate_version = '11' @new_resource.stub!(:options).and_return("--disablerepo epmd") Chef::Provider::Package::Yum::RPMUtils.stub!(:rpmvercmp).and_return(-1) @provider.should_receive(:yum_command).with( "yum -d0 -e0 -y --disablerepo epmd install cups-11" ) @provider.install_package(@new_resource.name, @provider.candidate_version) end it "should raise an exception if the package is not available" do @yum_cache = mock( 'Chef::Provider::Yum::YumCache', :reload_from_cache => true, :reset => true, :installed_version => "1.2.4-11.18.el5", :candidate_version => "1.2.4-11.18.el5_2.3", :package_available? => true, :version_available? => nil, :disable_extra_repo_control => true ) Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) lambda { @provider.install_package("lolcats", "0.99") }.should raise_error(Chef::Exceptions::Package, %r{Version .* not found}) end it "should raise an exception if candidate version is older than the installed version and allow_downgrade is false" do @new_resource.stub!(:allow_downgrade).and_return(false) @yum_cache = mock( 'Chef::Provider::Yum::YumCache', :reload_installed => true, :reset => true, :installed_version => "1.2.4-11.18.el5", :candidate_version => "1.2.4-11.15.el5", :package_available? => true, :version_available? => true, :allow_multi_install => [ "kernel" ], :disable_extra_repo_control => true ) Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) @provider.load_current_resource lambda { @provider.install_package("cups", "1.2.4-11.15.el5") }.should raise_error(Chef::Exceptions::Package, %r{is newer than candidate package}) end it "should not raise an exception if candidate version is older than the installed version and the package is list in yum's installonlypkg option" do @yum_cache = mock( 'Chef::Provider::Yum::YumCache', :reload_installed => true, :reset => true, :installed_version => "1.2.4-11.18.el5", :candidate_version => "1.2.4-11.15.el5", :package_available? => true, :version_available? => true, :allow_multi_install => [ "cups" ], :package_repository => "base", :disable_extra_repo_control => true ) Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) @provider.load_current_resource @provider.should_receive(:yum_command).with( "yum -d0 -e0 -y install cups-1.2.4-11.15.el5" ) @provider.install_package("cups", "1.2.4-11.15.el5") end it "should run yum downgrade if candidate version is older than the installed version and allow_downgrade is true" do @new_resource.stub!(:allow_downgrade).and_return(true) @yum_cache = mock( 'Chef::Provider::Yum::YumCache', :reload_installed => true, :reset => true, :installed_version => "1.2.4-11.18.el5", :candidate_version => "1.2.4-11.15.el5", :package_available? => true, :version_available? => true, :allow_multi_install => [], :package_repository => "base", :disable_extra_repo_control => true ) Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) @provider.load_current_resource @provider.should_receive(:yum_command).with( "yum -d0 -e0 -y downgrade cups-1.2.4-11.15.el5" ) @provider.install_package("cups", "1.2.4-11.15.el5") end it "should run yum install then flush the cache if :after is true" do @new_resource.stub!(:flush_cache).and_return({:after => true, :before => false}) @provider.load_current_resource Chef::Provider::Package::Yum::RPMUtils.stub!(:rpmvercmp).and_return(-1) @provider.should_receive(:yum_command).with( "yum -d0 -e0 -y install emacs-1.0" ) @yum_cache.should_receive(:reload).once @provider.install_package("emacs", "1.0") end it "should run yum install then not flush the cache if :after is false" do @new_resource.stub!(:flush_cache).and_return({:after => false, :before => false}) @provider.load_current_resource Chef::Provider::Package::Yum::RPMUtils.stub!(:rpmvercmp).and_return(-1) @provider.should_receive(:yum_command).with( "yum -d0 -e0 -y install emacs-1.0" ) @yum_cache.should_not_receive(:reload) @provider.install_package("emacs", "1.0") end end describe "when upgrading a package" do it "should run yum install if the package is installed and a version is given" do @provider.load_current_resource @provider.candidate_version = '11' Chef::Provider::Package::Yum::RPMUtils.stub!(:rpmvercmp).and_return(-1) @provider.should_receive(:yum_command).with( "yum -d0 -e0 -y install cups-11" ) @provider.upgrade_package(@new_resource.name, @provider.candidate_version) end it "should run yum install if the package is not installed" do @provider.load_current_resource @current_resource = Chef::Resource::Package.new('cups') @provider.candidate_version = '11' Chef::Provider::Package::Yum::RPMUtils.stub!(:rpmvercmp).and_return(-1) @provider.should_receive(:yum_command).with( "yum -d0 -e0 -y install cups-11" ) @provider.upgrade_package(@new_resource.name, @provider.candidate_version) end it "should raise an exception if candidate version is older than the installed version" do @yum_cache = mock( 'Chef::Provider::Yum::YumCache', :reload_installed => true, :reset => true, :installed_version => "1.2.4-11.18.el5", :candidate_version => "1.2.4-11.15.el5", :package_available? => true, :version_available? => true, :allow_multi_install => [ "kernel" ], :disable_extra_repo_control => true ) Chef::Provider::Package::Yum::YumCache.stub!(:instance).and_return(@yum_cache) @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) @provider.load_current_resource lambda { @provider.upgrade_package("cups", "1.2.4-11.15.el5") }.should raise_error(Chef::Exceptions::Package, %r{is newer than candidate package}) end # Test our little workaround, some crossover into Chef::Provider::Package territory it "should call action_upgrade in the parent if the current resource version is nil" do @yum_cache.stub!(:installed_version).and_return(nil) @provider.load_current_resource @current_resource = Chef::Resource::Package.new('cups') @provider.candidate_version = '11' @provider.should_receive(:upgrade_package).with( "cups", "11" ) @provider.action_upgrade end it "should call action_upgrade in the parent if the candidate version is nil" do @provider.load_current_resource @current_resource = Chef::Resource::Package.new('cups') @provider.candidate_version = nil @provider.should_not_receive(:upgrade_package) @provider.action_upgrade end it "should call action_upgrade in the parent if the candidate is newer" do @provider.load_current_resource @current_resource = Chef::Resource::Package.new('cups') @provider.candidate_version = '11' @provider.should_receive(:upgrade_package).with( "cups", "11" ) @provider.action_upgrade end it "should not call action_upgrade in the parent if the candidate is older" do @yum_cache.stub!(:installed_version).and_return("12") @provider.load_current_resource @current_resource = Chef::Resource::Package.new('cups') @provider.candidate_version = '11' @provider.should_not_receive(:upgrade_package) @provider.action_upgrade end end describe "when removing a package" do it "should run yum remove with the package name" do @provider.should_receive(:yum_command).with( "yum -d0 -e0 -y remove emacs-1.0" ) @provider.remove_package("emacs", "1.0") end it "should run yum remove with the package name and arch" do @new_resource.stub!(:arch).and_return("x86_64") @provider.should_receive(:yum_command).with( "yum -d0 -e0 -y remove emacs-1.0.x86_64" ) @provider.remove_package("emacs", "1.0") end end describe "when purging a package" do it "should run yum remove with the package name" do @provider.should_receive(:yum_command).with( "yum -d0 -e0 -y remove emacs-1.0" ) @provider.purge_package("emacs", "1.0") end end describe "when running yum" do it "should run yum once if it exits with a return code of 0" do @status = mock("Status", :exitstatus => 0) @provider.stub!(:output_of_command).and_return([@status, "", ""]) @provider.should_receive(:output_of_command).once.with( "yum -d0 -e0 -y install emacs-1.0", {:timeout => Chef::Config[:yum_timeout]} ) @provider.yum_command("yum -d0 -e0 -y install emacs-1.0") end it "should run yum once if it exits with a return code > 0 and no scriptlet failures" do @status = mock("Status", :exitstatus => 2) @provider.stub!(:output_of_command).and_return([@status, "failure failure", "problem problem"]) @provider.should_receive(:output_of_command).once.with( "yum -d0 -e0 -y install emacs-1.0", {:timeout => Chef::Config[:yum_timeout]} ) lambda { @provider.yum_command("yum -d0 -e0 -y install emacs-1.0") }.should raise_error(Chef::Exceptions::Exec) end it "should run yum once if it exits with a return code of 1 and %pre scriptlet failures" do @status = mock("Status", :exitstatus => 1) @provider.stub!(:output_of_command).and_return([@status, "error: %pre(demo-1-1.el5.centos.x86_64) scriptlet failed, exit status 2", ""]) @provider.should_receive(:output_of_command).once.with( "yum -d0 -e0 -y install emacs-1.0", {:timeout => Chef::Config[:yum_timeout]} ) # will still raise an exception, can't stub out the subsequent call lambda { @provider.yum_command("yum -d0 -e0 -y install emacs-1.0") }.should raise_error(Chef::Exceptions::Exec) end it "should run yum twice if it exits with a return code of 1 and %post scriptlet failures" do @status = mock("Status", :exitstatus => 1) @provider.stub!(:output_of_command).and_return([@status, "error: %post(demo-1-1.el5.centos.x86_64) scriptlet failed, exit status 2", ""]) @provider.should_receive(:output_of_command).twice.with( "yum -d0 -e0 -y install emacs-1.0", {:timeout => Chef::Config[:yum_timeout]} ) # will still raise an exception, can't stub out the subsequent call lambda { @provider.yum_command("yum -d0 -e0 -y install emacs-1.0") }.should raise_error(Chef::Exceptions::Exec) end end end describe Chef::Provider::Package::Yum::RPMUtils do describe "version_parse" do before do @rpmutils = Chef::Provider::Package::Yum::RPMUtils end it "parses known good epoch strings" do [ [ "0:3.3", [ 0, "3.3", nil ] ], [ "9:1.7.3", [ 9, "1.7.3", nil ] ], [ "15:20020927", [ 15, "20020927", nil ] ] ].each do |x, y| @rpmutils.version_parse(x).should == y end end it "parses strange epoch strings" do [ [ ":3.3", [ 0, "3.3", nil ] ], [ "-1:1.7.3", [ nil, nil, "1:1.7.3" ] ], [ "-:20020927", [ nil, nil, ":20020927" ] ] ].each do |x, y| @rpmutils.version_parse(x).should == y end end it "parses known good version strings" do [ [ "3.3", [ nil, "3.3", nil ] ], [ "1.7.3", [ nil, "1.7.3", nil ] ], [ "20020927", [ nil, "20020927", nil ] ] ].each do |x, y| @rpmutils.version_parse(x).should == y end end it "parses strange version strings" do [ [ "3..3", [ nil, "3..3", nil ] ], [ "0001.7.3", [ nil, "0001.7.3", nil ] ], [ "20020927,3", [ nil, "20020927,3", nil ] ] ].each do |x, y| @rpmutils.version_parse(x).should == y end end it "parses known good version release strings" do [ [ "3.3-0.pre3.1.60.el5_5.1", [ nil, "3.3", "0.pre3.1.60.el5_5.1" ] ], [ "1.7.3-1jpp.2.el5", [ nil, "1.7.3", "1jpp.2.el5" ] ], [ "20020927-46.el5", [ nil, "20020927", "46.el5" ] ] ].each do |x, y| @rpmutils.version_parse(x).should == y end end it "parses strange version release strings" do [ [ "3.3-", [ nil, "3.3", nil ] ], [ "-1jpp.2.el5", [ nil, nil, "1jpp.2.el5" ] ], [ "-0020020927-46.el5", [ nil, "-0020020927", "46.el5" ] ] ].each do |x, y| @rpmutils.version_parse(x).should == y end end end describe "rpmvercmp" do before do @rpmutils = Chef::Provider::Package::Yum::RPMUtils end it "should validate version compare logic for standard examples" do [ # numeric [ "0.0.2", "0.0.1", 1 ], [ "0.2.0", "0.1.0", 1 ], [ "2.0.0", "1.0.0", 1 ], [ "0.0.1", "0.0.1", 0 ], [ "0.0.1", "0.0.2", -1 ], [ "0.1.0", "0.2.0", -1 ], [ "1.0.0", "2.0.0", -1 ], # alpha [ "bb", "aa", 1 ], [ "ab", "aa", 1 ], [ "aa", "aa", 0 ], [ "aa", "bb", -1 ], [ "aa", "ab", -1 ], [ "BB", "AA", 1 ], [ "AA", "AA", 0 ], [ "AA", "BB", -1 ], [ "aa", "AA", 1 ], [ "AA", "aa", -1 ], # alphanumeric [ "0.0.1b", "0.0.1a", 1 ], [ "0.1b.0", "0.1a.0", 1 ], [ "1b.0.0", "1a.0.0", 1 ], [ "0.0.1a", "0.0.1a", 0 ], [ "0.0.1a", "0.0.1b", -1 ], [ "0.1a.0", "0.1b.0", -1 ], [ "1a.0.0", "1b.0.0", -1 ], # alphanumeric against alphanumeric [ "0.0.1", "0.0.a", 1 ], [ "0.1.0", "0.a.0", 1 ], [ "1.0.0", "a.0.0", 1 ], [ "0.0.a", "0.0.a", 0 ], [ "0.0.a", "0.0.1", -1 ], [ "0.a.0", "0.1.0", -1 ], [ "a.0.0", "1.0.0", -1 ], # alphanumeric against numeric [ "0.0.2", "0.0.1a", 1 ], [ "0.0.2a", "0.0.1", 1 ], [ "0.0.1", "0.0.2a", -1 ], [ "0.0.1a", "0.0.2", -1 ], # length [ "0.0.1aa", "0.0.1a", 1 ], [ "0.0.1aa", "0.0.1aa", 0 ], [ "0.0.1a", "0.0.1aa", -1 ], ].each do |x, y, result| @rpmutils.rpmvercmp(x,y).should == result end end it "should validate version compare logic for strange examples" do [ [ "2,0,0", "1.0.0", 1 ], [ "0.0.1", "0,0.1", 0 ], [ "1.0.0", "2,0,0", -1 ], [ "002.0.0", "001.0.0", 1 ], [ "001..0.1", "001..0.0", 1 ], [ "-001..1", "-001..0", 1 ], [ "1.0.1", nil, 1 ], [ nil, nil, 0 ], [ nil, "1.0.1", -1 ], [ "1.0.1", "", 1 ], [ "", "", 0 ], [ "", "1.0.1", -1 ] ].each do |x, y, result| @rpmutils.rpmvercmp(x,y).should == result end end it "tests isalnum good input" do [ 'a', 'z', 'A', 'Z', '0', '9' ].each do |t| @rpmutils.isalnum(t).should == true end end it "tests isalnum bad input" do [ '-', '.', '!', '^', ':', '_' ].each do |t| @rpmutils.isalnum(t).should == false end end it "tests isalpha good input" do [ 'a', 'z', 'A', 'Z', ].each do |t| @rpmutils.isalpha(t).should == true end end it "tests isalpha bad input" do [ '0', '9', '-', '.', '!', '^', ':', '_' ].each do |t| @rpmutils.isalpha(t).should == false end end it "tests isdigit good input" do [ '0', '9', ].each do |t| @rpmutils.isdigit(t).should == true end end it "tests isdigit bad input" do [ 'A', 'z', '-', '.', '!', '^', ':', '_' ].each do |t| @rpmutils.isdigit(t).should == false end end end end describe Chef::Provider::Package::Yum::RPMVersion do describe "new - with parsing" do before do @rpmv = Chef::Provider::Package::Yum::RPMVersion.new("1:1.6.5-9.36.el5") end it "should expose evr (name-version-release) available" do @rpmv.e.should == 1 @rpmv.v.should == "1.6.5" @rpmv.r.should == "9.36.el5" @rpmv.evr.should == "1:1.6.5-9.36.el5" end it "should output a version-release string" do @rpmv.to_s.should == "1.6.5-9.36.el5" end end describe "new - no parsing" do before do @rpmv = Chef::Provider::Package::Yum::RPMVersion.new("1", "1.6.5", "9.36.el5") end it "should expose evr (name-version-release) available" do @rpmv.e.should == 1 @rpmv.v.should == "1.6.5" @rpmv.r.should == "9.36.el5" @rpmv.evr.should == "1:1.6.5-9.36.el5" end it "should output a version-release string" do @rpmv.to_s.should == "1.6.5-9.36.el5" end end it "should raise an error unless passed 1 or 3 args" do lambda { Chef::Provider::Package::Yum::RPMVersion.new() }.should raise_error(ArgumentError) lambda { Chef::Provider::Package::Yum::RPMVersion.new("1:1.6.5-9.36.el5") }.should_not raise_error lambda { Chef::Provider::Package::Yum::RPMVersion.new("1:1.6.5-9.36.el5", "extra") }.should raise_error(ArgumentError) lambda { Chef::Provider::Package::Yum::RPMVersion.new("1", "1.6.5", "9.36.el5") }.should_not raise_error lambda { Chef::Provider::Package::Yum::RPMVersion.new("1", "1.6.5", "9.36.el5", "extra") }.should raise_error(ArgumentError) end # thanks version_class_spec.rb! describe "compare" do it "should sort based on complete epoch-version-release data" do [ # smaller, larger [ "0:1.6.5-9.36.el5", "1:1.6.5-9.36.el5" ], [ "0:2.3-15.el5", "0:3.3-15.el5" ], [ "0:alpha9.8-27.2", "0:beta9.8-27.2" ], [ "0:0.09-14jpp.3", "0:0.09-15jpp.3" ], [ "0:0.9.0-0.6.20110211.el5", "0:0.9.0-0.6.20120211.el5" ], [ "0:1.9.1-4.el5", "0:1.9.1-5.el5" ], [ "0:1.4.10-7.20090624svn.el5", "0:1.4.10-7.20090625svn.el5" ], [ "0:2.3.4-2.el5", "0:2.3.4-2.el6" ] ].each do |smaller, larger| sm = Chef::Provider::Package::Yum::RPMVersion.new(smaller) lg = Chef::Provider::Package::Yum::RPMVersion.new(larger) sm.should be < lg lg.should be > sm sm.should_not == lg end end it "should sort based on partial epoch-version-release data" do [ # smaller, larger [ ":1.6.5-9.36.el5", "1:1.6.5-9.36.el5" ], [ "2.3-15.el5", "3.3-15.el5" ], [ "alpha9.8", "beta9.8" ], [ "14jpp", "15jpp" ], [ "0.9.0-0.6", "0.9.0-0.7" ], [ "0:1.9", "3:1.9" ], [ "2.3-2.el5", "2.3-2.el6" ] ].each do |smaller, larger| sm = Chef::Provider::Package::Yum::RPMVersion.new(smaller) lg = Chef::Provider::Package::Yum::RPMVersion.new(larger) sm.should be < lg lg.should be > sm sm.should_not == lg end end it "should verify equality of complete epoch-version-release data" do [ [ "0:1.6.5-9.36.el5", "0:1.6.5-9.36.el5" ], [ "0:2.3-15.el5", "0:2.3-15.el5" ], [ "0:alpha9.8-27.2", "0:alpha9.8-27.2" ] ].each do |smaller, larger| sm = Chef::Provider::Package::Yum::RPMVersion.new(smaller) lg = Chef::Provider::Package::Yum::RPMVersion.new(larger) sm.should be == lg end end it "should verify equality of partial epoch-version-release data" do [ [ ":1.6.5-9.36.el5", "0:1.6.5-9.36.el5" ], [ "2.3-15.el5", "2.3-15.el5" ], [ "alpha9.8-3", "alpha9.8-3" ] ].each do |smaller, larger| sm = Chef::Provider::Package::Yum::RPMVersion.new(smaller) lg = Chef::Provider::Package::Yum::RPMVersion.new(larger) sm.should be == lg end end end describe "partial compare" do it "should compare based on partial epoch-version-release data" do [ # smaller, larger [ "0:1.1.1-1", "1:" ], [ "0:1.1.1-1", "0:1.1.2" ], [ "0:1.1.1-1", "0:1.1.2-1" ], [ "0:", "1:1.1.1-1" ], [ "0:1.1.1", "0:1.1.2-1" ], [ "0:1.1.1-1", "0:1.1.2-1" ], ].each do |smaller, larger| sm = Chef::Provider::Package::Yum::RPMVersion.new(smaller) lg = Chef::Provider::Package::Yum::RPMVersion.new(larger) sm.partial_compare(lg).should be == -1 lg.partial_compare(sm).should be == 1 sm.partial_compare(lg).should_not be == 0 end end it "should verify equality based on partial epoch-version-release data" do [ [ "0:", "0:1.1.1-1" ], [ "0:1.1.1", "0:1.1.1-1" ], [ "0:1.1.1-1", "0:1.1.1-1" ], ].each do |smaller, larger| sm = Chef::Provider::Package::Yum::RPMVersion.new(smaller) lg = Chef::Provider::Package::Yum::RPMVersion.new(larger) sm.partial_compare(lg).should be == 0 end end end end describe Chef::Provider::Package::Yum::RPMPackage do describe "new - with parsing" do before do @rpm = Chef::Provider::Package::Yum::RPMPackage.new("testing", "1:1.6.5-9.36.el5", "x86_64", []) end it "should expose nevra (name-epoch-version-release-arch) available" do @rpm.name.should == "testing" @rpm.version.e.should == 1 @rpm.version.v.should == "1.6.5" @rpm.version.r.should == "9.36.el5" @rpm.arch.should == "x86_64" @rpm.nevra.should == "testing-1:1.6.5-9.36.el5.x86_64" @rpm.to_s.should == @rpm.nevra end it "should always have at least one provide, itself" do @rpm.provides.size.should == 1 @rpm.provides[0].name == "testing" @rpm.provides[0].version.evr == "1:1.6.5-9.36.el5" @rpm.provides[0].flag == :== end end describe "new - no parsing" do before do @rpm = Chef::Provider::Package::Yum::RPMPackage.new("testing", "1", "1.6.5", "9.36.el5", "x86_64", []) end it "should expose nevra (name-epoch-version-release-arch) available" do @rpm.name.should == "testing" @rpm.version.e.should == 1 @rpm.version.v.should == "1.6.5" @rpm.version.r.should == "9.36.el5" @rpm.arch.should == "x86_64" @rpm.nevra.should == "testing-1:1.6.5-9.36.el5.x86_64" @rpm.to_s.should == @rpm.nevra end it "should always have at least one provide, itself" do @rpm.provides.size.should == 1 @rpm.provides[0].name == "testing" @rpm.provides[0].version.evr == "1:1.6.5-9.36.el5" @rpm.provides[0].flag == :== end end it "should raise an error unless passed 4 or 6 args" do lambda { Chef::Provider::Package::Yum::RPMPackage.new() }.should raise_error(ArgumentError) lambda { Chef::Provider::Package::Yum::RPMPackage.new("testing") }.should raise_error(ArgumentError) lambda { Chef::Provider::Package::Yum::RPMPackage.new("testing", "1:1.6.5-9.36.el5") }.should raise_error(ArgumentError) lambda { Chef::Provider::Package::Yum::RPMPackage.new("testing", "1:1.6.5-9.36.el5", "x86_64") }.should raise_error(ArgumentError) lambda { Chef::Provider::Package::Yum::RPMPackage.new("testing", "1:1.6.5-9.36.el5", "x86_64", []) }.should_not raise_error lambda { Chef::Provider::Package::Yum::RPMPackage.new("testing", "1", "1.6.5", "9.36.el5", "x86_64") }.should raise_error(ArgumentError) lambda { Chef::Provider::Package::Yum::RPMPackage.new("testing", "1", "1.6.5", "9.36.el5", "x86_64", []) }.should_not raise_error lambda { Chef::Provider::Package::Yum::RPMPackage.new("testing", "1", "1.6.5", "9.36.el5", "x86_64", [], "extra") }.should raise_error(ArgumentError) end describe "<=>" do it "should sort alphabetically based on package name" do [ [ "a-test", "b-test" ], [ "B-test", "a-test" ], [ "A-test", "B-test" ], [ "Aa-test", "aA-test" ], [ "1test", "2test" ], ].each do |smaller, larger| sm = Chef::Provider::Package::Yum::RPMPackage.new(smaller, "0:0.0.1-1", "x86_64", []) lg = Chef::Provider::Package::Yum::RPMPackage.new(larger, "0:0.0.1-1", "x86_64", []) sm.should be < lg lg.should be > sm sm.should_not == lg end end it "should sort alphabetically based on package arch" do [ [ "i386", "x86_64" ], [ "i386", "noarch" ], [ "noarch", "x86_64" ], ].each do |smaller, larger| sm = Chef::Provider::Package::Yum::RPMPackage.new("test-package", "0:0.0.1-1", smaller, []) lg = Chef::Provider::Package::Yum::RPMPackage.new("test-package", "0:0.0.1-1", larger, []) sm.should be < lg lg.should be > sm sm.should_not == lg end end end end describe Chef::Provider::Package::Yum::RPMDbPackage do before(:each) do # name, version, arch, installed, available, repoid @rpm_x = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-b", "0:1.6.5-9.36.el5", "noarch", [], false, true, "base") @rpm_y = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-b", "0:1.6.5-9.36.el5", "noarch", [], true, true, "extras") @rpm_z = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-b", "0:1.6.5-9.36.el5", "noarch", [], true, false, "other") end describe "initialize" do it "should return a Chef::Provider::Package::Yum::RPMDbPackage object" do @rpm_x.should be_kind_of(Chef::Provider::Package::Yum::RPMDbPackage) end end describe "available" do it "should return true" do @rpm_x.available.should be == true @rpm_y.available.should be == true @rpm_z.available.should be == false end end describe "installed" do it "should return true" do @rpm_x.installed.should be == false @rpm_y.installed.should be == true @rpm_z.installed.should be == true end end describe "repoid" do it "should return the source repository repoid" do @rpm_x.repoid.should be == "base" @rpm_y.repoid.should be == "extras" @rpm_z.repoid.should be == "other" end end end describe Chef::Provider::Package::Yum::RPMDependency do describe "new - with parsing" do before do @rpmdep = Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :==) end it "should expose name, version, flag available" do @rpmdep.name.should == "testing" @rpmdep.version.e.should == 1 @rpmdep.version.v.should == "1.6.5" @rpmdep.version.r.should == "9.36.el5" @rpmdep.flag.should == :== end end describe "new - no parsing" do before do @rpmdep = Chef::Provider::Package::Yum::RPMDependency.new("testing", "1", "1.6.5", "9.36.el5", :==) end it "should expose name, version, flag available" do @rpmdep.name.should == "testing" @rpmdep.version.e.should == 1 @rpmdep.version.v.should == "1.6.5" @rpmdep.version.r.should == "9.36.el5" @rpmdep.flag.should == :== end end it "should raise an error unless passed 3 or 5 args" do lambda { Chef::Provider::Package::Yum::RPMDependency.new() }.should raise_error(ArgumentError) lambda { Chef::Provider::Package::Yum::RPMDependency.new("testing") }.should raise_error(ArgumentError) lambda { Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5") }.should raise_error(ArgumentError) lambda { Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :==) }.should_not raise_error lambda { Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :==, "extra") }.should raise_error(ArgumentError) lambda { Chef::Provider::Package::Yum::RPMDependency.new("testing", "1", "1.6.5", "9.36.el5", :==) }.should_not raise_error lambda { Chef::Provider::Package::Yum::RPMDependency.new("testing", "1", "1.6.5", "9.36.el5", :==, "extra") }.should raise_error(ArgumentError) end describe "parse" do it "should parse a name, flag, version string into a valid RPMDependency object" do @rpmdep = Chef::Provider::Package::Yum::RPMDependency.parse("testing >= 1:1.6.5-9.36.el5") @rpmdep.name.should == "testing" @rpmdep.version.e.should == 1 @rpmdep.version.v.should == "1.6.5" @rpmdep.version.r.should == "9.36.el5" @rpmdep.flag.should == :>= end it "should parse a name into a valid RPMDependency object" do @rpmdep = Chef::Provider::Package::Yum::RPMDependency.parse("testing") @rpmdep.name.should == "testing" @rpmdep.version.e.should == nil @rpmdep.version.v.should == nil @rpmdep.version.r.should == nil @rpmdep.flag.should == :== end it "should parse an invalid string into the name of a RPMDependency object" do @rpmdep = Chef::Provider::Package::Yum::RPMDependency.parse("testing blah >") @rpmdep.name.should == "testing blah >" @rpmdep.version.e.should == nil @rpmdep.version.v.should == nil @rpmdep.version.r.should == nil @rpmdep.flag.should == :== end it "should parse various valid flags" do [ [ ">", :> ], [ ">=", :>= ], [ "=", :== ], [ "==", :== ], [ "<=", :<= ], [ "<", :< ] ].each do |before, after| @rpmdep = Chef::Provider::Package::Yum::RPMDependency.parse("testing #{before} 1:1.1-1") @rpmdep.flag.should == after end end it "should parse various invalid flags and treat them as names" do [ [ "<>", :== ], [ "!=", :== ], [ ">>", :== ], [ "<<", :== ], [ "!", :== ], [ "~", :== ] ].each do |before, after| @rpmdep = Chef::Provider::Package::Yum::RPMDependency.parse("testing #{before} 1:1.1-1") @rpmdep.name.should == "testing #{before} 1:1.1-1" @rpmdep.flag.should == after end end end describe "satisfy?" do it "should raise an error unless a RPMDependency is passed" do @rpmprovide = Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :==) @rpmrequire = Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :>=) lambda { @rpmprovide.satisfy?("hi") }.should raise_error(ArgumentError) lambda { @rpmprovide.satisfy?(@rpmrequire) }.should_not raise_error end it "should validate dependency satisfaction logic for standard examples" do [ # names [ "test", "test", true ], [ "test", "foo", false ], # full: epoch:version-relese [ "testing = 1:1.1-1", "testing > 1:1.1-0", true ], [ "testing = 1:1.1-1", "testing >= 1:1.1-0", true ], [ "testing = 1:1.1-1", "testing >= 1:1.1-1", true ], [ "testing = 1:1.1-1", "testing = 1:1.1-1", true ], [ "testing = 1:1.1-1", "testing == 1:1.1-1", true ], [ "testing = 1:1.1-1", "testing <= 1:1.1-1", true ], [ "testing = 1:1.1-1", "testing <= 1:1.1-0", false ], [ "testing = 1:1.1-1", "testing < 1:1.1-0", false ], # partial: epoch:version [ "testing = 1:1.1", "testing > 1:1.0", true ], [ "testing = 1:1.1", "testing >= 1:1.0", true ], [ "testing = 1:1.1", "testing >= 1:1.1", true ], [ "testing = 1:1.1", "testing = 1:1.1", true ], [ "testing = 1:1.1", "testing == 1:1.1", true ], [ "testing = 1:1.1", "testing <= 1:1.1", true ], [ "testing = 1:1.1", "testing <= 1:1.0", false ], [ "testing = 1:1.1", "testing < 1:1.0", false ], # partial: epoch [ "testing = 1:", "testing > 0:", true ], [ "testing = 1:", "testing >= 0:", true ], [ "testing = 1:", "testing >= 1:", true ], [ "testing = 1:", "testing = 1:", true ], [ "testing = 1:", "testing == 1:", true ], [ "testing = 1:", "testing <= 1:", true ], [ "testing = 1:", "testing <= 0:", false ], [ "testing = 1:", "testing < 0:", false ], # mix and match! [ "testing = 1:1.1-1", "testing == 1:1.1", true ], [ "testing = 1:1.1-1", "testing == 1:", true ], ].each do |prov, req, result| @rpmprovide = Chef::Provider::Package::Yum::RPMDependency.parse(prov) @rpmrequire = Chef::Provider::Package::Yum::RPMDependency.parse(req) @rpmprovide.satisfy?(@rpmrequire).should == result @rpmrequire.satisfy?(@rpmprovide).should == result end end end end # thanks resource_collection_spec.rb! describe Chef::Provider::Package::Yum::RPMDb do before(:each) do @rpmdb = Chef::Provider::Package::Yum::RPMDb.new # name, version, arch, installed, available deps_v = [ Chef::Provider::Package::Yum::RPMDependency.parse("libz.so.1()(64bit)"), Chef::Provider::Package::Yum::RPMDependency.parse("test-package-a = 0:1.6.5-9.36.el5") ] deps_z = [ Chef::Provider::Package::Yum::RPMDependency.parse("libz.so.1()(64bit)"), Chef::Provider::Package::Yum::RPMDependency.parse("config(test) = 0:1.6.5-9.36.el5"), Chef::Provider::Package::Yum::RPMDependency.parse("test-package-c = 0:1.6.5-9.36.el5") ] @rpm_v = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-a", "0:1.6.5-9.36.el5", "i386", deps_v, true, false, "base") @rpm_w = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-b", "0:1.6.5-9.36.el5", "i386", [], true, true, "extras") @rpm_x = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-b", "0:1.6.5-9.36.el5", "x86_64", [], false, true, "extras") @rpm_y = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-b", "1:1.6.5-9.36.el5", "x86_64", [], true, true, "extras") @rpm_z = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-c", "0:1.6.5-9.36.el5", "noarch", deps_z, true, true, "base") @rpm_z_mirror = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-c", "0:1.6.5-9.36.el5", "noarch", deps_z, true, true, "base") end describe "initialize" do it "should return a Chef::Provider::Package::Yum::RPMDb object" do @rpmdb.should be_kind_of(Chef::Provider::Package::Yum::RPMDb) end end describe "push" do it "should accept an RPMDbPackage object through pushing" do lambda { @rpmdb.push(@rpm_w) }.should_not raise_error end it "should accept multiple RPMDbPackage object through pushing" do lambda { @rpmdb.push(@rpm_w, @rpm_x, @rpm_y, @rpm_z) }.should_not raise_error end it "should only accept an RPMDbPackage object" do lambda { @rpmdb.push("string") }.should raise_error end it "should add the package to the package db" do @rpmdb.push(@rpm_w) @rpmdb["test-package-b"].should_not be == nil end it "should add conditionally add the package to the available list" do @rpmdb.available_size.should be == 0 @rpmdb.push(@rpm_v, @rpm_w) @rpmdb.available_size.should be == 1 end it "should add conditionally add the package to the installed list" do @rpmdb.installed_size.should be == 0 @rpmdb.push(@rpm_w, @rpm_x) @rpmdb.installed_size.should be == 1 end it "should have a total of 2 packages in the RPMDb" do @rpmdb.size.should be == 0 @rpmdb.push(@rpm_w, @rpm_x, @rpm_y, @rpm_z) @rpmdb.size.should be == 2 end it "should keep the Array unique when a duplicate is pushed" do @rpmdb.push(@rpm_z, @rpm_z_mirror) @rpmdb["test-package-c"].size.should be == 1 end it "should register the package provides in the provides index" do @rpmdb.push(@rpm_v, @rpm_w, @rpm_z) @rpmdb.lookup_provides("test-package-a")[0].should be == @rpm_v @rpmdb.lookup_provides("config(test)")[0].should be == @rpm_z @rpmdb.lookup_provides("libz.so.1()(64bit)")[0].should be == @rpm_v @rpmdb.lookup_provides("libz.so.1()(64bit)")[1].should be == @rpm_z end end describe "<<" do it "should accept an RPMPackage object through the << operator" do lambda { @rpmdb << @rpm_w }.should_not raise_error end end describe "lookup" do it "should return an Array of RPMPackage objects by index" do @rpmdb << @rpm_w @rpmdb.lookup("test-package-b").should be_kind_of(Array) end end describe "[]" do it "should return an Array of RPMPackage objects though the [index] operator" do @rpmdb << @rpm_w @rpmdb["test-package-b"].should be_kind_of(Array) end it "should return an Array of 3 RPMPackage objects" do @rpmdb.push(@rpm_w, @rpm_x, @rpm_y, @rpm_z) @rpmdb["test-package-b"].size.should be == 3 end it "should return an Array of RPMPackage objects sorted from newest to oldest" do @rpmdb.push(@rpm_w, @rpm_x, @rpm_y, @rpm_z) @rpmdb["test-package-b"][0].should be == @rpm_y @rpmdb["test-package-b"][1].should be == @rpm_x @rpmdb["test-package-b"][2].should be == @rpm_w end end describe "lookup_provides" do it "should return an Array of RPMPackage objects by index" do @rpmdb << @rpm_z x = @rpmdb.lookup_provides("config(test)") x.should be_kind_of(Array) x[0].should be == @rpm_z end end describe "clear" do it "should clear the RPMDb" do @rpmdb.should_receive(:clear_available).once @rpmdb.should_receive(:clear_installed).once @rpmdb.push(@rpm_w, @rpm_x, @rpm_y, @rpm_z) @rpmdb.size.should_not be == 0 @rpmdb.lookup_provides("config(test)").should be_kind_of(Array) @rpmdb.clear @rpmdb.lookup_provides("config(test)").should be == nil @rpmdb.size.should be == 0 end end describe "clear_available" do it "should clear the available list" do @rpmdb.push(@rpm_w, @rpm_x, @rpm_y, @rpm_z) @rpmdb.available_size.should_not be == 0 @rpmdb.clear_available @rpmdb.available_size.should be == 0 end end describe "available?" do it "should return true if a package is available" do @rpmdb.available?(@rpm_w).should be == false @rpmdb.push(@rpm_v, @rpm_w) @rpmdb.available?(@rpm_v).should be == false @rpmdb.available?(@rpm_w).should be == true end end describe "clear_installed" do it "should clear the installed list" do @rpmdb.push(@rpm_w, @rpm_x, @rpm_y, @rpm_z) @rpmdb.installed_size.should_not be == 0 @rpmdb.clear_installed @rpmdb.installed_size.should be == 0 end end describe "installed?" do it "should return true if a package is installed" do @rpmdb.installed?(@rpm_w).should be == false @rpmdb.push(@rpm_w, @rpm_x) @rpmdb.installed?(@rpm_w).should be == true @rpmdb.installed?(@rpm_x).should be == false end end describe "whatprovides" do it "should raise an error unless a RPMDependency is passed" do @rpmprovide = Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :==) @rpmrequire = Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :>=) lambda { @rpmdb.whatprovides("hi") }.should raise_error(ArgumentError) lambda { @rpmdb.whatprovides(@rpmrequire) }.should_not raise_error end it "should return an Array of packages statisfying a RPMDependency" do @rpmdb.push(@rpm_v, @rpm_w, @rpm_z) @rpmrequire = Chef::Provider::Package::Yum::RPMDependency.parse("test-package-a >= 1.6.5") x = @rpmdb.whatprovides(@rpmrequire) x.should be_kind_of(Array) x[0].should be == @rpm_v @rpmrequire = Chef::Provider::Package::Yum::RPMDependency.parse("libz.so.1()(64bit)") x = @rpmdb.whatprovides(@rpmrequire) x.should be_kind_of(Array) x[0].should be == @rpm_v x[1].should be == @rpm_z end end end describe Chef::Provider::Package::Yum::YumCache do # allow for the reset of a Singleton # thanks to Ian White (http://blog.ardes.com/2006/12/11/testing-singletons-with-ruby) class << Chef::Provider::Package::Yum::YumCache def reset_instance Singleton.send :__init__, self self end end before(:each) do @stdin = mock("STDIN", :nil_object => true) @stdout = mock("STDOUT", :nil_object => true) @stdout_good = < 0, :stdin => @stdin, :stdout => @stdout_good, :stderr => @stderr) # new singleton each time Chef::Provider::Package::Yum::YumCache.reset_instance @yc = Chef::Provider::Package::Yum::YumCache.instance # load valid data @yc.stub!(:shell_out!).and_return(@status) end describe "initialize" do it "should return a Chef::Provider::Package::Yum::YumCache object" do @yc.should be_kind_of(Chef::Provider::Package::Yum::YumCache) end it "should register reload for start of Chef::Client runs" do Chef::Provider::Package::Yum::YumCache.reset_instance Chef::Client.should_receive(:when_run_starts) do |&b| b.should_not be_nil end @yc = Chef::Provider::Package::Yum::YumCache.instance end end describe "refresh" do it "should implicitly call yum-dump.py only once by default after being instantiated" do @yc.should_receive(:shell_out!).once @yc.installed_version("zlib") @yc.reset @yc.installed_version("zlib") end it "should run yum-dump.py using the system python when next_refresh is for :all" do @yc.reload @yc.should_receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --options --installed-provides$}, :timeout=>Chef::Config[:yum_timeout]) @yc.refresh end it "should run yum-dump.py with the installed flag when next_refresh is for :installed" do @yc.reload_installed @yc.should_receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --installed$}, :timeout=>Chef::Config[:yum_timeout]) @yc.refresh end it "should run yum-dump.py with the all-provides flag when next_refresh is for :provides" do @yc.reload_provides @yc.should_receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --options --all-provides$}, :timeout=>Chef::Config[:yum_timeout]) @yc.refresh end it "should pass extra_repo_control args to yum-dump.py" do @yc.enable_extra_repo_control("--enablerepo=foo --disablerepo=bar") @yc.should_receive(:shell_out!).with(%r{^/usr/bin/python .*/yum-dump.py --options --installed-provides --enablerepo=foo --disablerepo=bar$}, :timeout=>Chef::Config[:yum_timeout]) @yc.refresh end it "should warn about invalid data with too many separators" do @status = mock("Status", :exitstatus => 0, :stdin => @stdin, :stdout => @stdout_bad_separators, :stderr => @stderr) @yc.stub!(:shell_out!).and_return(@status) Chef::Log.should_receive(:warn).exactly(3).times.with(%r{Problem parsing}) @yc.refresh end it "should warn about invalid data with an incorrect type" do @status = mock("Status", :exitstatus => 0, :stdin => @stdin, :stdout => @stdout_bad_type, :stderr => @stderr) @yc.stub!(:shell_out!).and_return(@status) Chef::Log.should_receive(:warn).exactly(2).times.with(%r{Problem parsing}) @yc.refresh end it "should warn about no output from yum-dump.py" do @status = mock("Status", :exitstatus => 0, :stdin => @stdin, :stdout => @stdout_no_output, :stderr => @stderr) @yc.stub!(:shell_out!).and_return(@status) Chef::Log.should_receive(:warn).exactly(1).times.with(%r{no output from yum-dump.py}) @yc.refresh end it "should raise exception yum-dump.py exits with a non zero status" do @status = mock("Status", :exitstatus => 1, :stdin => @stdin, :stdout => @stdout_no_output, :stderr => @stderr) @yc.stub!(:shell_out!).and_return(@status) lambda { @yc.refresh}.should raise_error(Chef::Exceptions::Package, %r{CentOS-Base.repo, line: 12}) end it "should parse type 'i' into an installed state for a package" do @yc.available_version("erlang-mochiweb").should be == nil @yc.installed_version("erlang-mochiweb").should_not be == nil end it "should parse type 'a' into an available state for a package" do @yc.available_version("znc").should_not be == nil @yc.installed_version("znc").should be == nil end it "should parse type 'r' into an installed and available states for a package" do @yc.available_version("zip").should_not be == nil @yc.installed_version("zip").should_not be == nil end it "should parse installonlypkgs from yum-dump.py options output" do @yc.allow_multi_install.should be == %w{kernel kernel-bigmem kernel-enterprise} end end describe "installed_version" do it "should take one or two arguments" do lambda { @yc.installed_version("zip") }.should_not raise_error(ArgumentError) lambda { @yc.installed_version("zip", "i386") }.should_not raise_error(ArgumentError) lambda { @yc.installed_version("zip", "i386", "extra") }.should raise_error(ArgumentError) end it "should return version-release for matching package regardless of arch" do @yc.installed_version("zip", "x86_64").should be == "2.31-2.el5" @yc.installed_version("zip", nil).should be == "2.31-2.el5" end it "should return version-release for matching package and arch" do @yc.installed_version("zip", "x86_64").should be == "2.31-2.el5" @yc.installed_version("zisofs-tools", "i386").should be == nil end it "should return nil for an unmatched package" do @yc.installed_version(nil, nil).should be == nil @yc.installed_version("test1", nil).should be == nil @yc.installed_version("test2", "x86_64").should be == nil end end describe "available_version" do it "should take one or two arguments" do lambda { @yc.available_version("zisofs-tools") }.should_not raise_error(ArgumentError) lambda { @yc.available_version("zisofs-tools", "i386") }.should_not raise_error(ArgumentError) lambda { @yc.available_version("zisofs-tools", "i386", "extra") }.should raise_error(ArgumentError) end it "should return version-release for matching package regardless of arch" do @yc.available_version("zip", "x86_64").should be == "2.31-2.el5" @yc.available_version("zip", nil).should be == "2.31-2.el5" end it "should return version-release for matching package and arch" do @yc.available_version("zip", "x86_64").should be == "2.31-2.el5" @yc.available_version("zisofs-tools", "i386").should be == nil end it "should return nil for an unmatched package" do @yc.available_version(nil, nil).should be == nil @yc.available_version("test1", nil).should be == nil @yc.available_version("test2", "x86_64").should be == nil end end describe "version_available?" do it "should take two or three arguments" do lambda { @yc.version_available?("zisofs-tools") }.should raise_error(ArgumentError) lambda { @yc.version_available?("zisofs-tools", "1.0.6-3.2.2") }.should_not raise_error(ArgumentError) lambda { @yc.version_available?("zisofs-tools", "1.0.6-3.2.2", "x86_64") }.should_not raise_error(ArgumentError) end it "should return true if our package-version-arch is available" do @yc.version_available?("zisofs-tools", "1.0.6-3.2.2", "x86_64").should be == true end it "should return true if our package-version, no arch, is available" do @yc.version_available?("zisofs-tools", "1.0.6-3.2.2", nil).should be == true @yc.version_available?("zisofs-tools", "1.0.6-3.2.2").should be == true end it "should return false if our package-version-arch isn't available" do @yc.version_available?("zisofs-tools", "1.0.6-3.2.2", "pretend").should be == false @yc.version_available?("zisofs-tools", "pretend", "x86_64").should be == false @yc.version_available?("pretend", "1.0.6-3.2.2", "x86_64").should be == false end it "should return false if our package-version, no arch, isn't available" do @yc.version_available?("zisofs-tools", "pretend", nil).should be == false @yc.version_available?("zisofs-tools", "pretend").should be == false @yc.version_available?("pretend", "1.0.6-3.2.2").should be == false end end describe "package_repository" do it "should take two or three arguments" do lambda { @yc.package_repository("zisofs-tools") }.should raise_error(ArgumentError) lambda { @yc.package_repository("zisofs-tools", "1.0.6-3.2.2") }.should_not raise_error(ArgumentError) lambda { @yc.package_repository("zisofs-tools", "1.0.6-3.2.2", "x86_64") }.should_not raise_error(ArgumentError) end it "should return repoid for package-version-arch" do @yc.package_repository("zlib-devel", "1.2.3-3", "i386").should be == "extras" @yc.package_repository("zlib-devel", "1.2.3-3", "x86_64").should be == "base" end it "should return repoid for package-version, no arch" do @yc.package_repository("zisofs-tools", "1.0.6-3.2.2", nil).should be == "extras" @yc.package_repository("zisofs-tools", "1.0.6-3.2.2").should be == "extras" end it "should return nil when no match for package-version-arch" do @yc.package_repository("zisofs-tools", "1.0.6-3.2.2", "pretend").should be == nil @yc.package_repository("zisofs-tools", "pretend", "x86_64").should be == nil @yc.package_repository("pretend", "1.0.6-3.2.2", "x86_64").should be == nil end it "should return nil when no match for package-version, no arch" do @yc.package_repository("zisofs-tools", "pretend", nil).should be == nil @yc.package_repository("zisofs-tools", "pretend").should be == nil @yc.package_repository("pretend", "1.0.6-3.2.2").should be == nil end end describe "reset" do it "should empty the installed and available packages RPMDb" do @yc.available_version("zip", "x86_64").should be == "2.31-2.el5" @yc.installed_version("zip", "x86_64").should be == "2.31-2.el5" @yc.reset @yc.available_version("zip", "x86_64").should be == nil @yc.installed_version("zip", "x86_64").should be == nil end end describe "package_available?" do it "should return true a package name is available" do @yc.package_available?("zisofs-tools").should be == true @yc.package_available?("moo").should be == false @yc.package_available?(nil).should be == false end it "should return true a package name + arch is available" do @yc.package_available?("zlib-devel.i386").should be == true @yc.package_available?("zisofs-tools.x86_64").should be == true @yc.package_available?("znc-test.beta1.x86_64").should be == true @yc.package_available?("znc-test.beta1").should be == true @yc.package_available?("znc-test.test.beta1").should be == true @yc.package_available?("moo.i386").should be == false @yc.package_available?("zisofs-tools.beta").should be == false @yc.package_available?("znc-test.test").should be == false end end describe "enable_extra_repo_control" do it "should set @extra_repo_control to arg" do @yc.enable_extra_repo_control("--enablerepo=test") @yc.extra_repo_control.should be == "--enablerepo=test" end it "should call reload once when set to flag cache for update" do @yc.should_receive(:reload).once @yc.enable_extra_repo_control("--enablerepo=test") @yc.enable_extra_repo_control("--enablerepo=test") end end describe "disable_extra_repo_control" do it "should set @extra_repo_control to nil" do @yc.enable_extra_repo_control("--enablerepo=test") @yc.disable_extra_repo_control @yc.extra_repo_control.should be == nil end it "should call reload once when cleared to flag cache for update" do @yc.should_receive(:reload).once @yc.enable_extra_repo_control("--enablerepo=test") @yc.should_receive(:reload).once @yc.disable_extra_repo_control @yc.disable_extra_repo_control end end end chef-11.8.2/spec/unit/provider/package/easy_install_spec.rb0000644000004100000410000001001412254362222023720 0ustar www-datawww-data# # Author:: Joe Williams () # Copyright:: Copyright (c) 2009 Joe Williams # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Package::EasyInstall do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::EasyInstallPackage.new('boto') @new_resource.version('1.8d') @current_resource = Chef::Resource::EasyInstallPackage.new('boto') @current_resource.version('1.8d') @provider = Chef::Provider::Package::EasyInstall.new(@new_resource, @run_context) Chef::Resource::Package.stub!(:new).and_return(@current_resource) @stdin = StringIO.new @stdout = StringIO.new @status = mock("Status", :exitstatus => 0) @stderr = StringIO.new @pid = 2342 @provider.stub!(:popen4).and_return(@status) end describe "easy_install_binary_path" do it "should return a Chef::Provider::EasyInstall object" do provider = Chef::Provider::Package::EasyInstall.new(@node, @new_resource) provider.should be_a_kind_of(Chef::Provider::Package::EasyInstall) end it "should set the current resources package name to the new resources package name" do $stdout.stub!(:write) @current_resource.should_receive(:package_name).with(@new_resource.package_name) @provider.load_current_resource end it "should return a relative path to easy_install if no easy_install_binary is given" do @provider.easy_install_binary_path.should eql("easy_install") end it "should return a specific path to easy_install if a easy_install_binary is given" do @new_resource.should_receive(:easy_install_binary).and_return("/opt/local/bin/custom/easy_install") @provider.easy_install_binary_path.should eql("/opt/local/bin/custom/easy_install") end end describe "actions_on_package" do it "should run easy_install with the package name and version" do @provider.should_receive(:run_command).with({ :command => "easy_install \"boto==1.8d\"" }) @provider.install_package("boto", "1.8d") end it "should run easy_install with the package name and version and specified options" do @provider.should_receive(:run_command).with({ :command => "easy_install --always-unzip \"boto==1.8d\"" }) @new_resource.stub!(:options).and_return("--always-unzip") @provider.install_package("boto", "1.8d") end it "should run easy_install with the package name and version" do @provider.should_receive(:run_command).with({ :command => "easy_install \"boto==1.8d\"" }) @provider.upgrade_package("boto", "1.8d") end it "should run easy_install -m with the package name and version" do @provider.should_receive(:run_command).with({ :command => "easy_install -m boto" }) @provider.remove_package("boto", "1.8d") end it "should run easy_install -m with the package name and version and specified options" do @provider.should_receive(:run_command).with({ :command => "easy_install -x -m boto" }) @new_resource.stub!(:options).and_return("-x") @provider.remove_package("boto", "1.8d") end it "should run easy_install -m with the package name and version" do @provider.should_receive(:run_command).with({ :command => "easy_install -m boto" }) @provider.purge_package("boto", "1.8d") end end end chef-11.8.2/spec/unit/provider/package/pacman_spec.rb0000644000004100000410000001723612254362222022505 0ustar www-datawww-data# # Author:: Jan Zimmek () # Copyright:: Copyright (c) 2010 Jan Zimmek # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Package::Pacman do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Package.new("nano") @current_resource = Chef::Resource::Package.new("nano") @status = mock("Status", :exitstatus => 0) @provider = Chef::Provider::Package::Pacman.new(@new_resource, @run_context) Chef::Resource::Package.stub!(:new).and_return(@current_resource) @provider.stub!(:popen4).and_return(@status) @stdin = StringIO.new @stdout = StringIO.new(<<-ERR) error: package "nano" not found ERR @stderr = StringIO.new @pid = 2342 end describe "when determining the current package state" do it "should create a current resource with the name of the new_resource" do Chef::Resource::Package.should_receive(:new).and_return(@current_resource) @provider.load_current_resource end it "should set the current resources package name to the new resources package name" do @current_resource.should_receive(:package_name).with(@new_resource.package_name) @provider.load_current_resource end it "should run pacman query with the package name" do @provider.should_receive(:popen4).with("pacman -Qi #{@new_resource.package_name}").and_return(@status) @provider.load_current_resource end it "should read stdout on pacman" do @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @stdout.should_receive(:each).and_return(true) @provider.load_current_resource end it "should set the installed version to nil on the current resource if pacman installed version not exists" do @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @current_resource.should_receive(:version).with(nil).and_return(true) @provider.load_current_resource end it "should set the installed version if pacman has one" do @stdout = StringIO.new(<<-PACMAN) Name : nano Version : 2.2.2-1 URL : http://www.nano-editor.org Licenses : GPL Groups : base Provides : None Depends On : glibc ncurses Optional Deps : None Required By : None Conflicts With : None Replaces : None Installed Size : 1496.00 K Packager : Andreas Radke Architecture : i686 Build Date : Mon 18 Jan 2010 06:16:16 PM CET Install Date : Mon 01 Feb 2010 10:06:30 PM CET Install Reason : Explicitly installed Install Script : Yes Description : Pico editor clone with enhancements PACMAN @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.load_current_resource @current_resource.version.should == "2.2.2-1" end it "should set the candidate version if pacman has one" do @stdout.stub!(:each).and_yield("core/nano 2.2.3-1 (base)"). and_yield(" Pico editor clone with enhancements"). and_yield("community/nanoblogger 3.4.1-1"). and_yield(" NanoBlogger is a small weblog engine written in Bash for the command line") @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.load_current_resource @provider.candidate_version.should eql("2.2.3-1") end it "should use pacman.conf to determine valid repo names for package versions" do @pacman_conf = <<-PACMAN_CONF [options] HoldPkg = pacman glibc Architecture = auto [customrepo] Server = https://my.custom.repo [core] Include = /etc/pacman.d/mirrorlist [extra] Include = /etc/pacman.d/mirrorlist [community] Include = /etc/pacman.d/mirrorlist PACMAN_CONF ::File.stub!(:exists?).with("/etc/pacman.conf").and_return(true) ::File.stub!(:read).with("/etc/pacman.conf").and_return(@pacman_conf) @stdout.stub!(:each).and_yield("customrepo/nano 1.2.3-4"). and_yield(" My custom package") @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.load_current_resource @provider.candidate_version.should eql("1.2.3-4") end it "should raise an exception if pacman fails" do @status.should_receive(:exitstatus).and_return(2) lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package) end it "should not raise an exception if pacman succeeds" do @status.should_receive(:exitstatus).and_return(0) lambda { @provider.load_current_resource }.should_not raise_error(Chef::Exceptions::Package) end it "should raise an exception if pacman does not return a candidate version" do @stdout.stub!(:each).and_yield("") @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) lambda { @provider.candidate_version }.should raise_error(Chef::Exceptions::Package) end it "should return the current resouce" do @provider.load_current_resource.should eql(@current_resource) end end describe Chef::Provider::Package::Pacman, "install_package" do it "should run pacman install with the package name and version" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "pacman --sync --noconfirm --noprogressbar nano" }) @provider.install_package("nano", "1.0") end it "should run pacman install with the package name and version and options if specified" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "pacman --sync --noconfirm --noprogressbar --debug nano" }) @new_resource.stub!(:options).and_return("--debug") @provider.install_package("nano", "1.0") end end describe Chef::Provider::Package::Pacman, "upgrade_package" do it "should run install_package with the name and version" do @provider.should_receive(:install_package).with("nano", "1.0") @provider.upgrade_package("nano", "1.0") end end describe Chef::Provider::Package::Pacman, "remove_package" do it "should run pacman remove with the package name" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "pacman --remove --noconfirm --noprogressbar nano" }) @provider.remove_package("nano", "1.0") end it "should run pacman remove with the package name and options if specified" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "pacman --remove --noconfirm --noprogressbar --debug nano" }) @new_resource.stub!(:options).and_return("--debug") @provider.remove_package("nano", "1.0") end end describe Chef::Provider::Package::Pacman, "purge_package" do it "should run remove_package with the name and version" do @provider.should_receive(:remove_package).with("nano", "1.0") @provider.purge_package("nano", "1.0") end end end chef-11.8.2/spec/unit/provider/package/rubygems_spec.rb0000644000004100000410000007121712254362222023102 0ustar www-datawww-data# # Author:: David Balatero (dbalatero@gmail.com) # # Copyright:: Copyright (c) 2009 David Balatero # License:: Apache License, Version 2.0 # # 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. # require 'pp' module GemspecBackcompatCreator def gemspec(name, version) if Gem::Specification.new.method(:initialize).arity == 0 Gem::Specification.new { |s| s.name = name; s.version = version } else Gem::Specification.new(name, version) end end end require 'spec_helper' require 'ostruct' describe Chef::Provider::Package::Rubygems::CurrentGemEnvironment do include GemspecBackcompatCreator before do @gem_env = Chef::Provider::Package::Rubygems::CurrentGemEnvironment.new end it "determines the gem paths from the in memory rubygems" do @gem_env.gem_paths.should == Gem.path end it "determines the installed versions of gems from Gem.source_index" do gems = [gemspec('rspec-core', Gem::Version.new('1.2.9')), gemspec('rspec-core', Gem::Version.new('1.3.0'))] if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.8.0') Gem::Specification.should_receive(:find_all_by_name).with('rspec-core', Gem::Dependency.new('rspec-core').requirement).and_return(gems) else Gem.source_index.should_receive(:search).with(Gem::Dependency.new('rspec-core', nil)).and_return(gems) end @gem_env.installed_versions(Gem::Dependency.new('rspec-core', nil)).should == gems end it "determines the installed versions of gems from the source index (part2: the unmockening)" do expected = ['rspec-core', Gem::Version.new(RSpec::Core::Version::STRING)] actual = @gem_env.installed_versions(Gem::Dependency.new('rspec-core', nil)).map { |spec| [spec.name, spec.version] } actual.should include(expected) end it "yields to a block with an alternate source list set" do sources_in_block = nil normal_sources = Gem.sources begin @gem_env.with_gem_sources("http://gems.example.org") do sources_in_block = Gem.sources raise RuntimeError, "sources should be reset even in case of an error" end rescue RuntimeError end sources_in_block.should == %w{http://gems.example.org} Gem.sources.should == normal_sources end it "it doesnt alter the gem sources if none are set" do sources_in_block = nil normal_sources = Gem.sources begin @gem_env.with_gem_sources(nil) do sources_in_block = Gem.sources raise RuntimeError, "sources should be reset even in case of an error" end rescue RuntimeError end sources_in_block.should == normal_sources Gem.sources.should == normal_sources end it "finds a matching gem candidate version" do dep = Gem::Dependency.new('rspec', '>= 0') dep_installer = Gem::DependencyInstaller.new @gem_env.stub!(:dependency_installer).and_return(dep_installer) latest = [[gemspec("rspec", Gem::Version.new("1.3.0")), "http://rubygems.org/"]] dep_installer.should_receive(:find_gems_with_sources).with(dep).and_return(latest) @gem_env.candidate_version_from_remote(Gem::Dependency.new('rspec', '>= 0')).should == Gem::Version.new('1.3.0') end it "finds a matching gem candidate version on rubygems 2.0.0+" do dep = Gem::Dependency.new('rspec', '>= 0') dep_installer = Gem::DependencyInstaller.new @gem_env.stub!(:dependency_installer).and_return(dep_installer) best_gem = mock("best gem match", :spec => gemspec("rspec", Gem::Version.new("1.3.0")), :source => "https://rubygems.org") available_set = mock("Gem::AvailableSet test double") available_set.should_receive(:pick_best!) available_set.should_receive(:set).and_return([best_gem]) dep_installer.should_receive(:find_gems_with_sources).with(dep).and_return(available_set) @gem_env.candidate_version_from_remote(Gem::Dependency.new('rspec', '>= 0')).should == Gem::Version.new('1.3.0') end context "when rubygems was upgraded from 1.8->2.0" do # https://github.com/rubygems/rubygems/issues/404 # tl;dr rubygems 1.8 and 2.0 can both be in the load path, which means that # require "rubygems/format" will load even though rubygems 2.0 doesn't have # that file. before do if defined?(Gem::Format) # tests are running under rubygems 1.8, or 2.0 upgraded from 1.8 @remove_gem_format = false else Gem.const_set(:Format, Object.new) @remove_gem_format = true end Gem::Package.stub!(:respond_to?).with(:open).and_return(false) end after do if @remove_gem_format Gem.send(:remove_const, :Format) end end it "finds a matching gem candidate version on rubygems 2.0+ with some rubygems 1.8 code loaded" do package = mock("Gem::Package", :spec => "a gemspec from package") Gem::Package.should_receive(:new).with("/path/to/package.gem").and_return(package) @gem_env.spec_from_file("/path/to/package.gem").should == "a gemspec from package" end end it "gives the candidate version as nil if none is found" do dep = Gem::Dependency.new('rspec', '>= 0') latest = [] dep_installer = Gem::DependencyInstaller.new @gem_env.stub!(:dependency_installer).and_return(dep_installer) dep_installer.should_receive(:find_gems_with_sources).with(dep).and_return(latest) @gem_env.candidate_version_from_remote(Gem::Dependency.new('rspec', '>= 0')).should be_nil end it "finds a matching candidate version from a .gem file when the path to the gem is supplied" do location = CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem' @gem_env.candidate_version_from_file(Gem::Dependency.new('chef-integration-test', '>= 0'), location).should == Gem::Version.new('0.1.0') @gem_env.candidate_version_from_file(Gem::Dependency.new('chef-integration-test', '>= 0.2.0'), location).should be_nil end it "finds a matching gem from a specific gemserver when explicit sources are given" do dep = Gem::Dependency.new('rspec', '>= 0') latest = [[gemspec("rspec", Gem::Version.new("1.3.0")), "http://rubygems.org/"]] @gem_env.should_receive(:with_gem_sources).with('http://gems.example.com').and_yield dep_installer = Gem::DependencyInstaller.new @gem_env.stub!(:dependency_installer).and_return(dep_installer) dep_installer.should_receive(:find_gems_with_sources).with(dep).and_return(latest) @gem_env.candidate_version_from_remote(Gem::Dependency.new('rspec', '>=0'), 'http://gems.example.com').should == Gem::Version.new('1.3.0') end it "installs a gem with a hash of options for the dependency installer" do dep_installer = Gem::DependencyInstaller.new @gem_env.should_receive(:dependency_installer).with(:install_dir => '/foo/bar').and_return(dep_installer) @gem_env.should_receive(:with_gem_sources).with('http://gems.example.com').and_yield dep_installer.should_receive(:install).with(Gem::Dependency.new('rspec', '>= 0')) @gem_env.install(Gem::Dependency.new('rspec', '>= 0'), :install_dir => '/foo/bar', :sources => ['http://gems.example.com']) end it "builds an uninstaller for a gem with options set to avoid requiring user input" do # default options for uninstaller should be: # :ignore => true, :executables => true Gem::Uninstaller.should_receive(:new).with('rspec', :ignore => true, :executables => true) @gem_env.uninstaller('rspec') end it "uninstalls all versions of a gem" do uninstaller = mock('gem uninstaller') uninstaller.should_receive(:uninstall) @gem_env.should_receive(:uninstaller).with('rspec', :all => true).and_return(uninstaller) @gem_env.uninstall('rspec') end it "uninstalls a specific version of a gem" do uninstaller = mock('gem uninstaller') uninstaller.should_receive(:uninstall) @gem_env.should_receive(:uninstaller).with('rspec', :version => '1.2.3').and_return(uninstaller) @gem_env.uninstall('rspec', '1.2.3') end end describe Chef::Provider::Package::Rubygems::AlternateGemEnvironment do include GemspecBackcompatCreator before do Chef::Provider::Package::Rubygems::AlternateGemEnvironment.gempath_cache.clear Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache.clear @gem_env = Chef::Provider::Package::Rubygems::AlternateGemEnvironment.new('/usr/weird/bin/gem') end it "determines the gem paths from shelling out to gem env" do gem_env_output = ['/path/to/gems', '/another/path/to/gems'].join(File::PATH_SEPARATOR) shell_out_result = OpenStruct.new(:stdout => gem_env_output) @gem_env.should_receive(:shell_out!).with('/usr/weird/bin/gem env gempath').and_return(shell_out_result) @gem_env.gem_paths.should == ['/path/to/gems', '/another/path/to/gems'] end it "caches the gempaths by gem_binary" do gem_env_output = ['/path/to/gems', '/another/path/to/gems'].join(File::PATH_SEPARATOR) shell_out_result = OpenStruct.new(:stdout => gem_env_output) @gem_env.should_receive(:shell_out!).with('/usr/weird/bin/gem env gempath').and_return(shell_out_result) expected = ['/path/to/gems', '/another/path/to/gems'] @gem_env.gem_paths.should == ['/path/to/gems', '/another/path/to/gems'] Chef::Provider::Package::Rubygems::AlternateGemEnvironment.gempath_cache['/usr/weird/bin/gem'].should == expected end it "uses the cached result for gem paths when available" do gem_env_output = ['/path/to/gems', '/another/path/to/gems'].join(File::PATH_SEPARATOR) shell_out_result = OpenStruct.new(:stdout => gem_env_output) @gem_env.should_not_receive(:shell_out!) expected = ['/path/to/gems', '/another/path/to/gems'] Chef::Provider::Package::Rubygems::AlternateGemEnvironment.gempath_cache['/usr/weird/bin/gem']= expected @gem_env.gem_paths.should == ['/path/to/gems', '/another/path/to/gems'] end it "builds the gems source index from the gem paths" do @gem_env.stub!(:gem_paths).and_return(['/path/to/gems', '/another/path/to/gems']) if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.8.0') @gem_env.gem_specification Gem::Specification.dirs.should == [ '/path/to/gems/specifications', '/another/path/to/gems/specifications' ] else Gem::SourceIndex.should_receive(:from_gems_in).with('/path/to/gems/specifications', '/another/path/to/gems/specifications') @gem_env.gem_source_index end end it "determines the installed versions of gems from the source index" do gems = [gemspec('rspec', Gem::Version.new('1.2.9')), gemspec('rspec', Gem::Version.new('1.3.0'))] rspec_dep = Gem::Dependency.new('rspec', nil) if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.8.0') @gem_env.stub!(:gem_specification).and_return(Gem::Specification) @gem_env.gem_specification.should_receive(:find_all_by_name).with(rspec_dep.name, rspec_dep.requirement).and_return(gems) else @gem_env.stub!(:gem_source_index).and_return(Gem.source_index) @gem_env.gem_source_index.should_receive(:search).with(rspec_dep).and_return(gems) end @gem_env.installed_versions(Gem::Dependency.new('rspec', nil)).should == gems end it "determines the installed versions of gems from the source index (part2: the unmockening)" do $stdout.stub!(:write) path_to_gem = if windows? `where gem`.split[1] else `which gem`.strip end pending("cant find your gem executable") if path_to_gem.empty? gem_env = Chef::Provider::Package::Rubygems::AlternateGemEnvironment.new(path_to_gem) expected = ['rspec-core', Gem::Version.new(RSpec::Core::Version::STRING)] actual = gem_env.installed_versions(Gem::Dependency.new('rspec-core', nil)).map { |s| [s.name, s.version] } actual.should include(expected) end it "detects when the target gem environment is the jruby platform" do gem_env_out=<<-JRUBY_GEM_ENV RubyGems Environment: - RUBYGEMS VERSION: 1.3.6 - RUBY VERSION: 1.8.7 (2010-05-12 patchlevel 249) [java] - INSTALLATION DIRECTORY: /Users/you/.rvm/gems/jruby-1.5.0 - RUBY EXECUTABLE: /Users/you/.rvm/rubies/jruby-1.5.0/bin/jruby - EXECUTABLE DIRECTORY: /Users/you/.rvm/gems/jruby-1.5.0/bin - RUBYGEMS PLATFORMS: - ruby - universal-java-1.6 - GEM PATHS: - /Users/you/.rvm/gems/jruby-1.5.0 - /Users/you/.rvm/gems/jruby-1.5.0@global - GEM CONFIGURATION: - :update_sources => true - :verbose => true - :benchmark => false - :backtrace => false - :bulk_threshold => 1000 - "install" => "--env-shebang" - "update" => "--env-shebang" - "gem" => "--no-rdoc --no-ri" - :sources => ["http://rubygems.org/", "http://gems.github.com/"] - REMOTE SOURCES: - http://rubygems.org/ - http://gems.github.com/ JRUBY_GEM_ENV @gem_env.should_receive(:shell_out!).with('/usr/weird/bin/gem env').and_return(mock('jruby_gem_env', :stdout => gem_env_out)) expected = ['ruby', Gem::Platform.new('universal-java-1.6')] @gem_env.gem_platforms.should == expected # it should also cache the result Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache['/usr/weird/bin/gem'].should == expected end it "uses the cached result for gem platforms if available" do @gem_env.should_not_receive(:shell_out!) expected = ['ruby', Gem::Platform.new('universal-java-1.6')] Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache['/usr/weird/bin/gem']= expected @gem_env.gem_platforms.should == expected end it "uses the current gem platforms when the target env is not jruby" do gem_env_out=<<-RBX_GEM_ENV RubyGems Environment: - RUBYGEMS VERSION: 1.3.6 - RUBY VERSION: 1.8.7 (2010-05-14 patchlevel 174) [x86_64-apple-darwin10.3.0] - INSTALLATION DIRECTORY: /Users/ddeleo/.rvm/gems/rbx-1.0.0-20100514 - RUBYGEMS PREFIX: /Users/ddeleo/.rvm/rubies/rbx-1.0.0-20100514 - RUBY EXECUTABLE: /Users/ddeleo/.rvm/rubies/rbx-1.0.0-20100514/bin/rbx - EXECUTABLE DIRECTORY: /Users/ddeleo/.rvm/gems/rbx-1.0.0-20100514/bin - RUBYGEMS PLATFORMS: - ruby - x86_64-darwin-10 - x86_64-rubinius-1.0 - GEM PATHS: - /Users/ddeleo/.rvm/gems/rbx-1.0.0-20100514 - /Users/ddeleo/.rvm/gems/rbx-1.0.0-20100514@global - GEM CONFIGURATION: - :update_sources => true - :verbose => true - :benchmark => false - :backtrace => false - :bulk_threshold => 1000 - :sources => ["http://rubygems.org/", "http://gems.github.com/"] - "gem" => "--no-rdoc --no-ri" - REMOTE SOURCES: - http://rubygems.org/ - http://gems.github.com/ RBX_GEM_ENV @gem_env.should_receive(:shell_out!).with('/usr/weird/bin/gem env').and_return(mock('rbx_gem_env', :stdout => gem_env_out)) @gem_env.gem_platforms.should == Gem.platforms Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache['/usr/weird/bin/gem'].should == Gem.platforms end it "yields to a block while masquerading as a different gems platform" do original_platforms = Gem.platforms platforms_in_block = nil begin @gem_env.with_gem_platforms(['ruby', Gem::Platform.new('sparc64-java-1.7')]) do platforms_in_block = Gem.platforms raise "gem platforms should get set to the correct value even when an error occurs" end rescue RuntimeError end platforms_in_block.should == ['ruby', Gem::Platform.new('sparc64-java-1.7')] Gem.platforms.should == original_platforms end end describe Chef::Provider::Package::Rubygems do before(:each) do @node = Chef::Node.new @new_resource = Chef::Resource::GemPackage.new("rspec-core") @spec_version = @new_resource.version RSpec::Core::Version::STRING @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) # We choose detect omnibus via RbConfig::CONFIG['bindir'] in Chef::Provider::Package::Rubygems.new RbConfig::CONFIG.stub!(:[]).with('bindir').and_return("/usr/bin/ruby") @provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context) end it "triggers a gem configuration load so a later one will not stomp its config values" do # ugly, is there a better way? Gem.instance_variable_get(:@configuration).should_not be_nil end it "uses the CurrentGemEnvironment implementation when no gem_binary_path is provided" do @provider.gem_env.should be_a_kind_of(Chef::Provider::Package::Rubygems::CurrentGemEnvironment) end it "uses the AlternateGemEnvironment implementation when a gem_binary_path is provided" do @new_resource.gem_binary('/usr/weird/bin/gem') provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context) provider.gem_env.gem_binary_location.should == '/usr/weird/bin/gem' end it "searches for a gem binary when running on Omnibus on Unix" do platform_mock :unix do RbConfig::CONFIG.stub!(:[]).with('bindir').and_return("/opt/chef/embedded/bin") ENV.stub!(:[]).with('PATH').and_return("/usr/bin:/usr/sbin:/opt/chef/embedded/bin") File.stub!(:exists?).with('/usr/bin/gem').and_return(false) File.stub!(:exists?).with('/usr/sbin/gem').and_return(true) File.stub!(:exists?).with('/opt/chef/embedded/bin/gem').and_return(true) # should not get here provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context) provider.gem_env.gem_binary_location.should == '/usr/sbin/gem' end end it "searches for a gem binary when running on Omnibus on Windows" do platform_mock :windows do RbConfig::CONFIG.stub!(:[]).with('bindir').and_return("d:/opscode/chef/embedded/bin") ENV.stub!(:[]).with('PATH').and_return('C:\windows\system32;C:\windows;C:\Ruby186\bin;d:\opscode\chef\embedded\bin') File.stub!(:exists?).with('C:\\windows\\system32\\gem').and_return(false) File.stub!(:exists?).with('C:\\windows\\gem').and_return(false) File.stub!(:exists?).with('C:\\Ruby186\\bin\\gem').and_return(true) File.stub!(:exists?).with('d:\\opscode\\chef\\bin\\gem').and_return(false) # should not get here File.stub!(:exists?).with('d:\\opscode\\chef\\embedded\\bin\\gem').and_return(false) # should not get here provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context) provider.gem_env.gem_binary_location.should == 'C:\Ruby186\bin\gem' end end it "smites you when you try to use a hash of install options with an explicit gem binary" do @new_resource.gem_binary('/foo/bar') @new_resource.options(:fail => :burger) lambda {Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)}.should raise_error(ArgumentError) end it "converts the new resource into a gem dependency" do @provider.gem_dependency.should == Gem::Dependency.new('rspec-core', @spec_version) @new_resource.version('~> 1.2.0') @provider.gem_dependency.should == Gem::Dependency.new('rspec-core', '~> 1.2.0') end describe "when determining the currently installed version" do it "sets the current version to the version specified by the new resource if that version is installed" do @provider.load_current_resource @provider.current_resource.version.should == @spec_version end it "sets the current version to the highest installed version if the requested version is not installed" do @new_resource.version('9000.0.2') @provider.load_current_resource @provider.current_resource.version.should == @spec_version end it "leaves the current version at nil if the package is not installed" do @new_resource.package_name("no-such-gem-should-exist-with-this-name") @provider.load_current_resource @provider.current_resource.version.should be_nil end end describe "when determining the candidate version to install" do it "does not query for available versions when the current version is the target version" do @provider.current_resource = @new_resource.dup @provider.candidate_version.should be_nil end it "determines the candidate version by querying the remote gem servers" do @new_resource.source('http://mygems.example.com') version = Gem::Version.new(@spec_version) @provider.gem_env.should_receive(:candidate_version_from_remote). with(Gem::Dependency.new('rspec-core', @spec_version), "http://mygems.example.com"). and_return(version) @provider.candidate_version.should == @spec_version end it "parses the gem's specification if the requested source is a file" do @new_resource.package_name('chef-integration-test') @new_resource.version('>= 0') @new_resource.source(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem') @provider.candidate_version.should == '0.1.0' end end describe "when installing a gem" do before do @current_resource = Chef::Resource::GemPackage.new('rspec-core') @provider.current_resource = @current_resource @gem_dep = Gem::Dependency.new('rspec-core', @spec_version) @provider.stub!(:load_current_resource) end describe "in the current gem environment" do it "installs the gem via the gems api when no explicit options are used" do @provider.gem_env.should_receive(:install).with(@gem_dep, :sources => nil) @provider.action_install.should be_true end it "installs the gem via the gems api when a remote source is provided" do @new_resource.source('http://gems.example.org') sources = ['http://gems.example.org'] @provider.gem_env.should_receive(:install).with(@gem_dep, :sources => sources) @provider.action_install.should be_true end it "installs the gem from file via the gems api when no explicit options are used" do @new_resource.source(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem') @provider.gem_env.should_receive(:install).with(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem') @provider.action_install.should be_true end it "installs the gem from file via the gems api when the package is a path and the source is nil" do @new_resource = Chef::Resource::GemPackage.new(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem') @provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context) @provider.current_resource = @current_resource @new_resource.source.should == CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem' @provider.gem_env.should_receive(:install).with(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem') @provider.action_install.should be_true end # this catches 'gem_package "foo"' when "./foo" is a file in the cwd, and instead of installing './foo' it fetches the remote gem it "installs the gem via the gems api, when the package has no file separator characters in it, but a matching file exists in cwd" do ::File.stub!(:exists?).and_return(true) @new_resource.package_name('rspec-core') @provider.gem_env.should_receive(:install).with(@gem_dep, :sources => nil) @provider.action_install.should be_true end it "installs the gem by shelling out when options are provided as a String" do @new_resource.options('-i /alt/install/location') expected ="gem install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\" -i /alt/install/location" @provider.should_receive(:shell_out!).with(expected, :env => nil) @provider.action_install.should be_true end it "installs the gem via the gems api when options are given as a Hash" do @new_resource.options(:install_dir => '/alt/install/location') @provider.gem_env.should_receive(:install).with(@gem_dep, :sources => nil, :install_dir => '/alt/install/location') @provider.action_install.should be_true end describe "at a specific version" do before do @gem_dep = Gem::Dependency.new('rspec-core', @spec_version) end it "installs the gem via the gems api" do @provider.gem_env.should_receive(:install).with(@gem_dep, :sources => nil) @provider.action_install.should be_true end end describe "at version specified with comparison operator" do it "skips install if current version satisifies requested version" do @current_resource.stub(:version).and_return("2.3.3") @new_resource.stub(:version).and_return(">=2.3.0") @provider.gem_env.should_not_receive(:install) @provider.action_install end it "allows user to specify gem version with fuzzy operator" do @current_resource.stub(:version).and_return("2.3.3") @new_resource.stub(:version).and_return("~>2.3.0") @provider.gem_env.should_not_receive(:install) @provider.action_install end end end describe "in an alternate gem environment" do it "installs the gem by shelling out to gem install" do @new_resource.gem_binary('/usr/weird/bin/gem') @provider.should_receive(:shell_out!).with("/usr/weird/bin/gem install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\"", :env=>nil) @provider.action_install.should be_true end it "installs the gem from file by shelling out to gem install" do @new_resource.gem_binary('/usr/weird/bin/gem') @new_resource.source(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem') @new_resource.version('>= 0') @provider.should_receive(:shell_out!).with("/usr/weird/bin/gem install #{CHEF_SPEC_DATA}/gems/chef-integration-test-0.1.0.gem -q --no-rdoc --no-ri -v \">= 0\"", :env=>nil) @provider.action_install.should be_true end it "installs the gem from file by shelling out to gem install when the package is a path and the source is nil" do @new_resource = Chef::Resource::GemPackage.new(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem') @provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context) @provider.current_resource = @current_resource @new_resource.gem_binary('/usr/weird/bin/gem') @new_resource.version('>= 0') @new_resource.source.should == CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem' @provider.should_receive(:shell_out!).with("/usr/weird/bin/gem install #{CHEF_SPEC_DATA}/gems/chef-integration-test-0.1.0.gem -q --no-rdoc --no-ri -v \">= 0\"", :env=>nil) @provider.action_install.should be_true end end end describe "when uninstalling a gem" do before do @new_resource = Chef::Resource::GemPackage.new("rspec") @current_resource = @new_resource.dup @current_resource.version('1.2.3') @provider.new_resource = @new_resource @provider.current_resource = @current_resource end describe "in the current gem environment" do it "uninstalls via the api when no explicit options are used" do # pre-reqs for action_remove to actually remove the package: @provider.new_resource.version.should be_nil @provider.current_resource.version.should_not be_nil # the behavior we're testing: @provider.gem_env.should_receive(:uninstall).with('rspec', nil) @provider.action_remove end it "uninstalls via the api when options are given as a Hash" do # pre-reqs for action_remove to actually remove the package: @provider.new_resource.version.should be_nil @provider.current_resource.version.should_not be_nil # the behavior we're testing: @new_resource.options(:install_dir => '/alt/install/location') @provider.gem_env.should_receive(:uninstall).with('rspec', nil, :install_dir => '/alt/install/location') @provider.action_remove end it "uninstalls via the gem command when options are given as a String" do @new_resource.options('-i /alt/install/location') @provider.should_receive(:shell_out!).with("gem uninstall rspec -q -x -I -a -i /alt/install/location", :env=>nil) @provider.action_remove end it "uninstalls a specific version of a gem when a version is provided" do @new_resource.version('1.2.3') @provider.gem_env.should_receive(:uninstall).with('rspec', '1.2.3') @provider.action_remove end end describe "in an alternate gem environment" do it "uninstalls via the gem command" do @new_resource.gem_binary('/usr/weird/bin/gem') @provider.should_receive(:shell_out!).with("/usr/weird/bin/gem uninstall rspec -q -x -I -a", :env=>nil) @provider.action_remove end end end end chef-11.8.2/spec/unit/provider/package/zypper_spec.rb0000644000004100000410000002170112254362222022567 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Package::Zypper do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Package.new("cups") @current_resource = Chef::Resource::Package.new("cups") @status = mock("Status", :exitstatus => 0) @provider = Chef::Provider::Package::Zypper.new(@new_resource, @run_context) Chef::Resource::Package.stub!(:new).and_return(@current_resource) @provider.stub!(:popen4).and_return(@status) @stderr = StringIO.new @stdout = StringIO.new @pid = mock("PID") @provider.stub!(:`).and_return("2.0") end describe "when loading the current package state" do it "should create a current resource with the name of the new_resource" do Chef::Resource::Package.should_receive(:new).and_return(@current_resource) @provider.load_current_resource end it "should set the current resources package name to the new resources package name" do @current_resource.should_receive(:package_name).with(@new_resource.package_name) @provider.load_current_resource end it "should run zypper info with the package name" do @provider.should_receive(:popen4).with("zypper --non-interactive info #{@new_resource.package_name}").and_return(@status) @provider.load_current_resource end it "should set the installed version to nil on the current resource if zypper info installed version is (none)" do @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @current_resource.should_receive(:version).with(nil).and_return(true) @provider.load_current_resource end it "should set the installed version if zypper info has one" do @stdout = StringIO.new("Version: 1.0\nInstalled: Yes\n") @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @current_resource.should_receive(:version).with("1.0").and_return(true) @provider.load_current_resource end it "should set the candidate version if zypper info has one" do @stdout = StringIO.new("Version: 1.0\nInstalled: No\nStatus: out-of-date (version 0.9 installed)") @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.load_current_resource @provider.candidate_version.should eql("1.0") end it "should raise an exception if zypper info fails" do @status.should_receive(:exitstatus).and_return(1) lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package) end it "should not raise an exception if zypper info succeeds" do @status.should_receive(:exitstatus).and_return(0) lambda { @provider.load_current_resource }.should_not raise_error(Chef::Exceptions::Package) end it "should return the current resouce" do @provider.load_current_resource.should eql(@current_resource) end end describe "install_package" do it "should run zypper install with the package name and version" do Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(true) @provider.should_receive(:shell_out!).with( "zypper --non-interactive install --auto-agree-with-licenses emacs=1.0") @provider.install_package("emacs", "1.0") end it "should run zypper install without gpg checks" do Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(false) @provider.should_receive(:shell_out!).with( "zypper --non-interactive --no-gpg-checks install "+ "--auto-agree-with-licenses emacs=1.0") @provider.install_package("emacs", "1.0") end it "should warn about gpg checks on zypper install" do Chef::Log.should_receive(:warn).with( /All packages will be installed without gpg signature checks/) @provider.should_receive(:shell_out!).with( "zypper --non-interactive --no-gpg-checks install "+ "--auto-agree-with-licenses emacs=1.0") @provider.install_package("emacs", "1.0") end end describe "upgrade_package" do it "should run zypper update with the package name and version" do Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(true) @provider.should_receive(:shell_out!).with( "zypper --non-interactive install --auto-agree-with-licenses emacs=1.0") @provider.upgrade_package("emacs", "1.0") end it "should run zypper update without gpg checks" do Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(false) @provider.should_receive(:shell_out!).with( "zypper --non-interactive --no-gpg-checks install "+ "--auto-agree-with-licenses emacs=1.0") @provider.upgrade_package("emacs", "1.0") end it "should warn about gpg checks on zypper upgrade" do Chef::Log.should_receive(:warn).with( /All packages will be installed without gpg signature checks/) @provider.should_receive(:shell_out!).with( "zypper --non-interactive --no-gpg-checks install "+ "--auto-agree-with-licenses emacs=1.0") @provider.upgrade_package("emacs", "1.0") end it "should run zypper upgrade without gpg checks" do @provider.should_receive(:shell_out!).with( "zypper --non-interactive --no-gpg-checks install "+ "--auto-agree-with-licenses emacs=1.0") @provider.upgrade_package("emacs", "1.0") end end describe "remove_package" do it "should run zypper remove with the package name" do Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(true) @provider.should_receive(:shell_out!).with( "zypper --non-interactive remove emacs=1.0") @provider.remove_package("emacs", "1.0") end it "should run zypper remove without gpg checks" do Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(false) @provider.should_receive(:shell_out!).with( "zypper --non-interactive --no-gpg-checks remove emacs=1.0") @provider.remove_package("emacs", "1.0") end it "should warn about gpg checks on zypper remove" do Chef::Log.should_receive(:warn).with( /All packages will be installed without gpg signature checks/) @provider.should_receive(:shell_out!).with( "zypper --non-interactive --no-gpg-checks remove emacs=1.0") @provider.remove_package("emacs", "1.0") end end describe "purge_package" do it "should run remove_package with the name and version" do @provider.should_receive(:shell_out!).with( "zypper --non-interactive --no-gpg-checks remove --clean-deps emacs=1.0") @provider.purge_package("emacs", "1.0") end it "should run zypper purge without gpg checks" do Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(false) @provider.should_receive(:shell_out!).with( "zypper --non-interactive --no-gpg-checks remove --clean-deps emacs=1.0") @provider.purge_package("emacs", "1.0") end it "should warn about gpg checks on zypper purge" do Chef::Log.should_receive(:warn).with( /All packages will be installed without gpg signature checks/) @provider.should_receive(:shell_out!).with( "zypper --non-interactive --no-gpg-checks remove --clean-deps emacs=1.0") @provider.purge_package("emacs", "1.0") end end describe "on an older zypper" do before(:each) do @provider.stub!(:`).and_return("0.11.6") end describe "install_package" do it "should run zypper install with the package name and version" do @provider.should_receive(:shell_out!).with( "zypper --no-gpg-checks install --auto-agree-with-licenses -y emacs") @provider.install_package("emacs", "1.0") end end describe "upgrade_package" do it "should run zypper update with the package name and version" do @provider.should_receive(:shell_out!).with( "zypper --no-gpg-checks install --auto-agree-with-licenses -y emacs") @provider.upgrade_package("emacs", "1.0") end end describe "remove_package" do it "should run zypper remove with the package name" do @provider.should_receive(:shell_out!).with( "zypper --no-gpg-checks remove -y emacs") @provider.remove_package("emacs", "1.0") end end end end chef-11.8.2/spec/unit/provider/package/rpm_spec.rb0000644000004100000410000001527212254362222022042 0ustar www-datawww-data# # Author:: Joshua Timberman () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008, 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Package::Rpm do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Package.new("emacs") @new_resource.source "/tmp/emacs-21.4-20.el5.i386.rpm" @provider = Chef::Provider::Package::Rpm.new(@new_resource, @run_context) @status = mock("Status", :exitstatus => 0) ::File.stub!(:exists?).and_return(true) end describe "when determining the current state of the package" do it "should create a current resource with the name of new_resource" do @provider.stub!(:popen4).and_return(@status) @provider.load_current_resource @provider.current_resource.name.should == "emacs" end it "should set the current reource package name to the new resource package name" do @provider.stub!(:popen4).and_return(@status) @provider.load_current_resource @provider.current_resource.package_name.should == 'emacs' end it "should raise an exception if a source is supplied but not found" do ::File.stub!(:exists?).and_return(false) lambda { @provider.run_action(:any) }.should raise_error(Chef::Exceptions::Package) end it "should get the source package version from rpm if provided" do @stdout = StringIO.new("emacs 21.4-20.el5") @provider.should_receive(:popen4).with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' /tmp/emacs-21.4-20.el5.i386.rpm").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.should_receive(:popen4).with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' emacs").and_return(@status) @provider.load_current_resource @provider.current_resource.package_name.should == "emacs" @provider.new_resource.version.should == "21.4-20.el5" end it "should return the current version installed if found by rpm" do @stdout = StringIO.new("emacs 21.4-20.el5") @provider.should_receive(:popen4).with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' /tmp/emacs-21.4-20.el5.i386.rpm").and_return(@status) @provider.should_receive(:popen4).with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' emacs").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.load_current_resource @provider.current_resource.version.should == "21.4-20.el5" end it "should raise an exception if the source is not set but we are installing" do new_resource = Chef::Resource::Package.new("emacs") provider = Chef::Provider::Package::Rpm.new(new_resource, @run_context) lambda { provider.run_action(:any) }.should raise_error(Chef::Exceptions::Package) end it "should raise an exception if rpm fails to run" do status = mock("Status", :exitstatus => -1) @provider.stub!(:popen4).and_return(status) lambda { @provider.run_action(:any) }.should raise_error(Chef::Exceptions::Package) end end describe "after the current resource is loaded" do before do @current_resource = Chef::Resource::Package.new("emacs") @provider.current_resource = @current_resource end describe "when installing or upgrading" do it "should run rpm -i with the package source to install" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "rpm -i /tmp/emacs-21.4-20.el5.i386.rpm" }) @provider.install_package("emacs", "21.4-20.el5") end it "should run rpm -U with the package source to upgrade" do @current_resource.version("21.4-19.el5") @provider.should_receive(:run_command_with_systems_locale).with({ :command => "rpm -U /tmp/emacs-21.4-20.el5.i386.rpm" }) @provider.upgrade_package("emacs", "21.4-20.el5") end it "should install from a path when the package is a path and the source is nil" do @new_resource = Chef::Resource::Package.new("/tmp/emacs-21.4-20.el5.i386.rpm") @provider = Chef::Provider::Package::Rpm.new(@new_resource, @run_context) @new_resource.source.should == "/tmp/emacs-21.4-20.el5.i386.rpm" @current_resource = Chef::Resource::Package.new("emacs") @provider.current_resource = @current_resource @provider.should_receive(:run_command_with_systems_locale).with({ :command => "rpm -i /tmp/emacs-21.4-20.el5.i386.rpm" }) @provider.install_package("/tmp/emacs-21.4-20.el5.i386.rpm", "21.4-20.el5") end it "should uprgrade from a path when the package is a path and the source is nil" do @new_resource = Chef::Resource::Package.new("/tmp/emacs-21.4-20.el5.i386.rpm") @provider = Chef::Provider::Package::Rpm.new(@new_resource, @run_context) @new_resource.source.should == "/tmp/emacs-21.4-20.el5.i386.rpm" @current_resource = Chef::Resource::Package.new("emacs") @current_resource.version("21.4-19.el5") @provider.current_resource = @current_resource @provider.should_receive(:run_command_with_systems_locale).with({ :command => "rpm -U /tmp/emacs-21.4-20.el5.i386.rpm" }) @provider.upgrade_package("/tmp/emacs-21.4-20.el5.i386.rpm", "21.4-20.el5") end it "installs with custom options specified in the resource" do @provider.candidate_version = '11' @new_resource.options("--dbpath /var/lib/rpm") @provider.should_receive(:run_command_with_systems_locale).with({ :command => "rpm --dbpath /var/lib/rpm -i /tmp/emacs-21.4-20.el5.i386.rpm" }) @provider.install_package(@new_resource.name, @provider.candidate_version) end end describe "when removing the package" do it "should run rpm -e to remove the package" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "rpm -e emacs-21.4-20.el5" }) @provider.remove_package("emacs", "21.4-20.el5") end end end end chef-11.8.2/spec/unit/provider/package/apt_spec.rb0000644000004100000410000002776612254362222022043 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'ostruct' describe Chef::Provider::Package::Apt do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Package.new("irssi", @run_context) @status = mock("Status", :exitstatus => 0) @provider = Chef::Provider::Package::Apt.new(@new_resource, @run_context) @stdin = StringIO.new @stdout =<<-PKG_STATUS irssi: Installed: (none) Candidate: 0.8.14-1ubuntu4 Version table: 0.8.14-1ubuntu4 0 500 http://us.archive.ubuntu.com/ubuntu/ lucid/main Packages PKG_STATUS @stderr = "" @shell_out = OpenStruct.new(:stdout => @stdout,:stdin => @stdin,:stderr => @stderr,:status => @status,:exitstatus => 0) end describe "when loading current resource" do it "should create a current resource with the name of the new_resource" do @provider.should_receive(:shell_out!).with("apt-cache policy #{@new_resource.package_name}").and_return(@shell_out) @provider.load_current_resource current_resource = @provider.current_resource current_resource.should be_a(Chef::Resource::Package) current_resource.name.should == "irssi" current_resource.package_name.should == "irssi" current_resource.version.should be_nil end it "should set the installed version if package has one" do @stdout.replace(<<-INSTALLED) sudo: Installed: 1.7.2p1-1ubuntu5.3 Candidate: 1.7.2p1-1ubuntu5.3 Version table: *** 1.7.2p1-1ubuntu5.3 0 500 http://us.archive.ubuntu.com/ubuntu/ lucid-updates/main Packages 500 http://security.ubuntu.com/ubuntu/ lucid-security/main Packages 100 /var/lib/dpkg/status 1.7.2p1-1ubuntu5 0 500 http://us.archive.ubuntu.com/ubuntu/ lucid/main Packages INSTALLED @provider.should_receive(:shell_out!).and_return(@shell_out) @provider.load_current_resource @provider.current_resource.version.should == "1.7.2p1-1ubuntu5.3" @provider.candidate_version.should eql("1.7.2p1-1ubuntu5.3") end # libmysqlclient-dev is a real package in newer versions of debian + ubuntu # list of virtual packages: http://www.debian.org/doc/packaging-manuals/virtual-package-names-list.txt it "should not install the virtual package there is a single provider package and it is installed" do @new_resource.package_name("libmysqlclient15-dev") virtual_package_out=<<-VPKG_STDOUT libmysqlclient15-dev: Installed: (none) Candidate: (none) Version table: VPKG_STDOUT virtual_package = mock(:stdout => virtual_package_out,:exitstatus => 0) @provider.should_receive(:shell_out!).with("apt-cache policy libmysqlclient15-dev").and_return(virtual_package) showpkg_out =<<-SHOWPKG_STDOUT Package: libmysqlclient15-dev Versions: Reverse Depends: libmysqlclient-dev,libmysqlclient15-dev libmysqlclient-dev,libmysqlclient15-dev libmysqlclient-dev,libmysqlclient15-dev libmysqlclient-dev,libmysqlclient15-dev libmysqlclient-dev,libmysqlclient15-dev libmysqlclient-dev,libmysqlclient15-dev Dependencies: Provides: Reverse Provides: libmysqlclient-dev 5.1.41-3ubuntu12.7 libmysqlclient-dev 5.1.41-3ubuntu12.10 libmysqlclient-dev 5.1.41-3ubuntu12 SHOWPKG_STDOUT showpkg = mock(:stdout => showpkg_out,:exitstatus => 0) @provider.should_receive(:shell_out!).with("apt-cache showpkg libmysqlclient15-dev").and_return(showpkg) real_package_out=<<-RPKG_STDOUT libmysqlclient-dev: Installed: 5.1.41-3ubuntu12.10 Candidate: 5.1.41-3ubuntu12.10 Version table: *** 5.1.41-3ubuntu12.10 0 500 http://us.archive.ubuntu.com/ubuntu/ lucid-updates/main Packages 100 /var/lib/dpkg/status 5.1.41-3ubuntu12.7 0 500 http://security.ubuntu.com/ubuntu/ lucid-security/main Packages 5.1.41-3ubuntu12 0 500 http://us.archive.ubuntu.com/ubuntu/ lucid/main Packages RPKG_STDOUT real_package = mock(:stdout => real_package_out,:exitstatus => 0) @provider.should_receive(:shell_out!).with("apt-cache policy libmysqlclient-dev").and_return(real_package) @provider.load_current_resource end it "should raise an exception if you specify a virtual package with multiple provider packages" do @new_resource.package_name("mp3-decoder") virtual_package_out=<<-VPKG_STDOUT mp3-decoder: Installed: (none) Candidate: (none) Version table: VPKG_STDOUT virtual_package = mock(:stdout => virtual_package_out,:exitstatus => 0) @provider.should_receive(:shell_out!).with("apt-cache policy mp3-decoder").and_return(virtual_package) showpkg_out=<<-SHOWPKG_STDOUT Package: mp3-decoder Versions: Reverse Depends: nautilus,mp3-decoder vux,mp3-decoder plait,mp3-decoder ecasound,mp3-decoder nautilus,mp3-decoder Dependencies: Provides: Reverse Provides: vlc-nox 1.0.6-1ubuntu1.8 vlc 1.0.6-1ubuntu1.8 vlc-nox 1.0.6-1ubuntu1 vlc 1.0.6-1ubuntu1 opencubicplayer 1:0.1.17-2 mpg321 0.2.10.6 mpg123 1.12.1-0ubuntu1 SHOWPKG_STDOUT showpkg = mock(:stdout => showpkg_out,:exitstatus => 0) @provider.should_receive(:shell_out!).with("apt-cache showpkg mp3-decoder").and_return(showpkg) lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package) end it "should run apt-cache policy with the default_release option, if there is one and provider is explicitly defined" do @new_resource = Chef::Resource::AptPackage.new("irssi", @run_context) @provider = Chef::Provider::Package::Apt.new(@new_resource, @run_context) @new_resource.stub!(:default_release).and_return("lenny-backports") @new_resource.stub!(:provider).and_return("Chef::Provider::Package::Apt") @provider.should_receive(:shell_out!).with("apt-cache -o APT::Default-Release=lenny-backports policy irssi").and_return(@shell_out) @provider.load_current_resource end end context "after loading the current resource" do before do @current_resource = Chef::Resource::Package.new("irssi", @run_context) @provider.current_resource = @current_resource end describe "install_package" do it "should run apt-get install with the package name and version" do @provider.should_receive(:shell_out!). with("apt-get -q -y install irssi=0.8.12-7", :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil}) @provider.install_package("irssi", "0.8.12-7") end it "should run apt-get install with the package name and version and options if specified" do @provider.should_receive(:shell_out!). with("apt-get -q -y --force-yes install irssi=0.8.12-7", :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }) @new_resource.options("--force-yes") @provider.install_package("irssi", "0.8.12-7") end it "should run apt-get install with the package name and version and default_release if there is one and provider is explicitly defined" do @new_resource = nil @new_resource = Chef::Resource::AptPackage.new("irssi", @run_context) @new_resource.default_release("lenny-backports") @provider.new_resource = @new_resource @provider.should_receive(:shell_out!). with("apt-get -q -y -o APT::Default-Release=lenny-backports install irssi=0.8.12-7", :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }) @provider.install_package("irssi", "0.8.12-7") end end describe Chef::Provider::Package::Apt, "upgrade_package" do it "should run install_package with the name and version" do @provider.should_receive(:install_package).with("irssi", "0.8.12-7") @provider.upgrade_package("irssi", "0.8.12-7") end end describe Chef::Provider::Package::Apt, "remove_package" do it "should run apt-get remove with the package name" do @provider.should_receive(:shell_out!). with("apt-get -q -y remove irssi", :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil}) @provider.remove_package("irssi", "0.8.12-7") end it "should run apt-get remove with the package name and options if specified" do @provider.should_receive(:shell_out!). with("apt-get -q -y --force-yes remove irssi", :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }) @new_resource.options("--force-yes") @provider.remove_package("irssi", "0.8.12-7") end end describe "when purging a package" do it "should run apt-get purge with the package name" do @provider.should_receive(:shell_out!). with("apt-get -q -y purge irssi", :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }) @provider.purge_package("irssi", "0.8.12-7") end it "should run apt-get purge with the package name and options if specified" do @provider.should_receive(:shell_out!). with("apt-get -q -y --force-yes purge irssi", :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }) @new_resource.options("--force-yes") @provider.purge_package("irssi", "0.8.12-7") end end describe "when preseeding a package" do before(:each) do @provider.stub!(:get_preseed_file).and_return("/tmp/irssi-0.8.12-7.seed") end it "should get the full path to the preseed response file" do @provider.should_receive(:get_preseed_file).with("irssi", "0.8.12-7").and_return("/tmp/irssi-0.8.12-7.seed") file = @provider.get_preseed_file("irssi", "0.8.12-7") @provider.should_receive(:shell_out!). with("debconf-set-selections /tmp/irssi-0.8.12-7.seed", :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil}) @provider.preseed_package(file) end it "should run debconf-set-selections on the preseed file if it has changed" do @provider.should_receive(:shell_out!). with("debconf-set-selections /tmp/irssi-0.8.12-7.seed", :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil}) file = @provider.get_preseed_file("irssi", "0.8.12-7") @provider.preseed_package(file) end it "should not run debconf-set-selections if the preseed file has not changed" do @provider.stub(:check_package_state) @current_resource.version "0.8.11" @new_resource.response_file "/tmp/file" @provider.stub!(:get_preseed_file).and_return(false) @provider.should_not_receive(:shell_out!) @provider.run_action(:reconfig) end end describe "when reconfiguring a package" do it "should run dpkg-reconfigure package" do @provider.should_receive(:shell_out!). with("dpkg-reconfigure irssi", :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }) @provider.reconfig_package("irssi", "0.8.12-7") end end describe "when installing a virtual package" do it "should install the package without specifying a version" do @provider.is_virtual_package = true @provider.should_receive(:shell_out!). with("apt-get -q -y install libmysqlclient-dev", :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }) @provider.install_package("libmysqlclient-dev", "not_a_real_version") end end end end chef-11.8.2/spec/unit/provider/package/dpkg_spec.rb0000644000004100000410000001777112254362222022177 0ustar www-datawww-data# # Author:: Bryan McLellan (btm@loftninjas.org) # Copyright:: Copyright (c) 2009 Bryan McLellan # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Package::Dpkg do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Package.new("wget") @new_resource.source "/tmp/wget_1.11.4-1ubuntu1_amd64.deb" @provider = Chef::Provider::Package::Dpkg.new(@new_resource, @run_context) @stdin = StringIO.new @stdout = StringIO.new @status = mock("Status", :exitstatus => 0) @stderr = StringIO.new @pid = mock("PID") @provider.stub!(:popen4).and_return(@status) ::File.stub!(:exists?).and_return(true) end describe "when loading the current resource state" do it "should create a current resource with the name of the new_resource" do @provider.load_current_resource @provider.current_resource.package_name.should == "wget" end it "should raise an exception if a source is supplied but not found" do @provider.load_current_resource @provider.define_resource_requirements ::File.stub!(:exists?).and_return(false) lambda { @provider.run_action(:install) }.should raise_error(Chef::Exceptions::Package) end describe 'gets the source package version from dpkg-deb' do def check_version(version) @stdout = StringIO.new("wget\t#{version}") @provider.stub!(:popen4).with("dpkg-deb -W #{@new_resource.source}").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.load_current_resource @provider.current_resource.package_name.should == "wget" @new_resource.version.should == version end it 'if short version provided' do check_version('1.11.4') end it 'if extended version provided' do check_version('1.11.4-1ubuntu1') end it 'if distro-specific version provided' do check_version('1.11.4-1ubuntu1~lucid') end end it "gets the source package name from dpkg-deb correctly when the package name has `-', `+' or `.' characters" do @stdout = StringIO.new("f.o.o-pkg++2\t1.11.4-1ubuntu1") @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.load_current_resource @provider.current_resource.package_name.should == "f.o.o-pkg++2" end it "should raise an exception if the source is not set but we are installing" do @new_resource = Chef::Resource::Package.new("wget") @provider.new_resource = @new_resource @provider.define_resource_requirements @provider.load_current_resource lambda { @provider.run_action(:install)}.should raise_error(Chef::Exceptions::Package) end it "should return the current version installed if found by dpkg" do @stdout = StringIO.new(<<-DPKG_S) Package: wget Status: install ok installed Priority: important Section: web Installed-Size: 1944 Maintainer: Ubuntu Core developers Architecture: amd64 Version: 1.11.4-1ubuntu1 Config-Version: 1.11.4-1ubuntu1 Depends: libc6 (>= 2.8~20080505), libssl0.9.8 (>= 0.9.8f-5) Conflicts: wget-ssl DPKG_S @provider.stub!(:popen4).with("dpkg -s wget").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.load_current_resource @provider.current_resource.version.should == "1.11.4-1ubuntu1" end it "should raise an exception if dpkg fails to run" do @status = mock("Status", :exitstatus => -1) @provider.stub!(:popen4).and_return(@status) lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package) end end describe Chef::Provider::Package::Dpkg, "install and upgrade" do it "should run dpkg -i with the package source" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "dpkg -i /tmp/wget_1.11.4-1ubuntu1_amd64.deb", :environment => { "DEBIAN_FRONTEND" => "noninteractive" } }) @provider.install_package("wget", "1.11.4-1ubuntu1") end it "should run dpkg -i if the package is a path and the source is nil" do @new_resource = Chef::Resource::Package.new("/tmp/wget_1.11.4-1ubuntu1_amd64.deb") @provider = Chef::Provider::Package::Dpkg.new(@new_resource, @run_context) @provider.should_receive(:run_command_with_systems_locale).with({ :command => "dpkg -i /tmp/wget_1.11.4-1ubuntu1_amd64.deb", :environment => { "DEBIAN_FRONTEND" => "noninteractive" } }) @provider.install_package("/tmp/wget_1.11.4-1ubuntu1_amd64.deb", "1.11.4-1ubuntu1") end it "should run dpkg -i if the package is a path and the source is nil for an upgrade" do @new_resource = Chef::Resource::Package.new("/tmp/wget_1.11.4-1ubuntu1_amd64.deb") @provider = Chef::Provider::Package::Dpkg.new(@new_resource, @run_context) @provider.should_receive(:run_command_with_systems_locale).with({ :command => "dpkg -i /tmp/wget_1.11.4-1ubuntu1_amd64.deb", :environment => { "DEBIAN_FRONTEND" => "noninteractive" } }) @provider.upgrade_package("/tmp/wget_1.11.4-1ubuntu1_amd64.deb", "1.11.4-1ubuntu1") end it "should run dpkg -i with the package source and options if specified" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "dpkg -i --force-yes /tmp/wget_1.11.4-1ubuntu1_amd64.deb", :environment => { "DEBIAN_FRONTEND" => "noninteractive" } }) @new_resource.stub!(:options).and_return("--force-yes") @provider.install_package("wget", "1.11.4-1ubuntu1") end it "should upgrade by running install_package" do @provider.should_receive(:install_package).with("wget", "1.11.4-1ubuntu1") @provider.upgrade_package("wget", "1.11.4-1ubuntu1") end end describe Chef::Provider::Package::Dpkg, "remove and purge" do it "should run dpkg -r to remove the package" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "dpkg -r wget", :environment => { "DEBIAN_FRONTEND" => "noninteractive" } }) @provider.remove_package("wget", "1.11.4-1ubuntu1") end it "should run dpkg -r to remove the package with options if specified" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "dpkg -r --force-yes wget", :environment => { "DEBIAN_FRONTEND" => "noninteractive" } }) @new_resource.stub!(:options).and_return("--force-yes") @provider.remove_package("wget", "1.11.4-1ubuntu1") end it "should run dpkg -P to purge the package" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "dpkg -P wget", :environment => { "DEBIAN_FRONTEND" => "noninteractive" } }) @provider.purge_package("wget", "1.11.4-1ubuntu1") end it "should run dpkg -P to purge the package with options if specified" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "dpkg -P --force-yes wget", :environment => { "DEBIAN_FRONTEND" => "noninteractive" } }) @new_resource.stub!(:options).and_return("--force-yes") @provider.purge_package("wget", "1.11.4-1ubuntu1") end end end chef-11.8.2/spec/unit/provider/package/ips_spec.rb0000644000004100000410000001762612254362222022044 0ustar www-datawww-data# # Author:: Bryan McLellan # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'ostruct' # based on the apt specs describe Chef::Provider::Package::Ips do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Package.new("crypto/gnupg", @run_context) @current_resource = Chef::Resource::Package.new("crypto/gnupg", @run_context) Chef::Resource::Package.stub!(:new).and_return(@current_resource) @provider = Chef::Provider::Package::Ips.new(@new_resource, @run_context) @stdin = StringIO.new @stderr = StringIO.new @stdout =<<-PKG_STATUS Name: crypto/gnupg Summary: GNU Privacy Guard Description: A complete and free implementation of the OpenPGP Standard as defined by RFC4880. Category: Applications/System Utilities State: Not installed Publisher: solaris Version: 2.0.17 Build Release: 5.11 Branch: 0.175.0.0.0.2.537 Packaging Date: October 19, 2011 09:14:50 AM Size: 8.07 MB FMRI: pkg://solaris/crypto/gnupg@2.0.17,5.11-0.175.0.0.0.2.537:20111019T091450Z PKG_STATUS @pid = 12345 @shell_out = OpenStruct.new(:stdout => @stdout,:stdin => @stdin,:stderr => @stderr,:status => @status,:exitstatus => 0) end context "when loading current resource" do it "should create a current resource with the name of the new_resource" do @provider.should_receive(:shell_out!).and_return(@shell_out) Chef::Resource::Package.should_receive(:new).and_return(@current_resource) @provider.load_current_resource end it "should set the current resources package name to the new resources package name" do @provider.should_receive(:shell_out!).and_return(@shell_out) @current_resource.should_receive(:package_name).with(@new_resource.package_name) @provider.load_current_resource end it "should run pkg info with the package name" do @provider.should_receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(@shell_out) @provider.load_current_resource end it "should set the installed version to nil on the current resource if package state is not installed" do @provider.should_receive(:shell_out!).and_return(@shell_out) @current_resource.should_receive(:version).with(nil).and_return(true) @provider.load_current_resource end it "should set the installed version if package has one" do @stdout.replace(<<-INSTALLED) Name: crypto/gnupg Summary: GNU Privacy Guard Description: A complete and free implementation of the OpenPGP Standard as defined by RFC4880. Category: Applications/System Utilities State: Installed Publisher: solaris Version: 2.0.17 Build Release: 5.11 Branch: 0.175.0.0.0.2.537 Packaging Date: October 19, 2011 09:14:50 AM Size: 8.07 MB FMRI: pkg://solaris/crypto/gnupg@2.0.17,5.11-0.175.0.0.0.2.537:20111019T091450Z INSTALLED @provider.should_receive(:shell_out!).and_return(@shell_out) @provider.load_current_resource @current_resource.version.should == "2.0.17" @provider.candidate_version.should eql("2.0.17") end it "should return the current resouce" do @provider.should_receive(:shell_out!).and_return(@shell_out) @provider.load_current_resource.should eql(@current_resource) end end context "when installing a package" do it "should run pkg install with the package name and version" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "pkg install -q crypto/gnupg@2.0.17" }) @provider.install_package("crypto/gnupg", "2.0.17") end it "should run pkg install with the package name and version and options if specified" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "pkg --no-refresh install -q crypto/gnupg@2.0.17" }) @new_resource.stub!(:options).and_return("--no-refresh") @provider.install_package("crypto/gnupg", "2.0.17") end it "should not contain invalid characters for the version string" do @stdout.replace(<<-PKG_STATUS) Name: security/sudo Summary: sudo - authority delegation tool State: Not Installed Publisher: omnios Version: 1.8.4.1 (1.8.4p1) Build Release: 5.11 Branch: 0.151002 Packaging Date: April 1, 2012 05:55:52 PM Size: 2.57 MB FMRI: pkg://omnios/security/sudo@1.8.4.1,5.11-0.151002:20120401T175552Z PKG_STATUS @provider.should_receive(:run_command_with_systems_locale).with({ :command => "pkg install -q security/sudo@1.8.4.1" }) @provider.install_package("security/sudo", "1.8.4.1") end it "should not include the human-readable version in the candidate_version" do @stdout.replace(<<-PKG_STATUS) Name: security/sudo Summary: sudo - authority delegation tool State: Not Installed Publisher: omnios Version: 1.8.4.1 (1.8.4p1) Build Release: 5.11 Branch: 0.151002 Packaging Date: April 1, 2012 05:55:52 PM Size: 2.57 MB FMRI: pkg://omnios/security/sudo@1.8.4.1,5.11-0.151002:20120401T175552Z PKG_STATUS @provider.should_receive(:shell_out!).and_return(@shell_out) @provider.load_current_resource @current_resource.version.should be_nil @provider.candidate_version.should eql("1.8.4.1") end context "using the ips_package resource" do before do @new_resource = Chef::Resource::IpsPackage.new("crypto/gnupg", @run_context) @current_resource = Chef::Resource::IpsPackage.new("crypto/gnupg", @run_context) @provider = Chef::Provider::Package::Ips.new(@new_resource, @run_context) end context "when accept_license is true" do before do @new_resource.stub!(:accept_license).and_return(true) end it "should run pkg install with the --accept flag" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "pkg install -q --accept crypto/gnupg@2.0.17" }) @provider.install_package("crypto/gnupg", "2.0.17") end end end end context "when upgrading a package" do it "should run pkg install with the package name and version" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "pkg install -q crypto/gnupg@2.0.17" }) @provider.upgrade_package("crypto/gnupg", "2.0.17") end end context "when uninstalling a package" do it "should run pkg uninstall with the package name and version" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "pkg uninstall -q crypto/gnupg@2.0.17" }) @provider.remove_package("crypto/gnupg", "2.0.17") end it "should run pkg uninstall with the package name and version and options if specified" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "pkg --no-refresh uninstall -q crypto/gnupg@2.0.17" }) @new_resource.stub!(:options).and_return("--no-refresh") @provider.remove_package("crypto/gnupg", "2.0.17") end end end chef-11.8.2/spec/unit/provider/package/smartos_spec.rb0000644000004100000410000000755712254362222022743 0ustar www-datawww-data# # Author:: Trevor O (trevoro@joyent.com) # Author:: Yukihiko Sawanobori (sawanoboriyu@higanworks.com) # Copyright:: Copyright (c) 2012 Opscode # License:: Apache License, Version 2.0 # # 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. # require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "spec_helper")) require 'ostruct' describe Chef::Provider::Package::SmartOS, "load_current_resource" do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Package.new("varnish") @current_resource = Chef::Resource::Package.new("varnish") @status = mock("Status", :exitstatus => 0) @provider = Chef::Provider::Package::SmartOS.new(@new_resource, @run_context) Chef::Resource::Package.stub!(:new).and_return(@current_resource) @stdin = StringIO.new @stdout = "varnish-2.1.5nb2\n" @stderr = StringIO.new @pid = 10 @shell_out = OpenStruct.new(:stdout => @stdout, :stdin => @stdin, :stderr => @stderr, :status => @status, :exitstatus => 0) end describe "when loading current resource" do it "should create a current resource with the name of the new_resource" do @provider.should_receive(:shell_out!).and_return(@shell_out) Chef::Resource::Package.should_receive(:new).and_return(@current_resource) @provider.load_current_resource end it "should set the current resource package name" do @provider.should_receive(:shell_out!).and_return(@shell_out) @current_resource.should_receive(:package_name).with(@new_resource.package_name) @provider.load_current_resource end it "should set the installed version if it is installed" do @provider.should_receive(:shell_out!).and_return(@shell_out) @provider.load_current_resource @current_resource.version.should == "2.1.5nb2" end it "should set the installed version to nil if it's not installed" do out = OpenStruct.new(:stdout => nil) @provider.should_receive(:shell_out!).and_return(out) @provider.load_current_resource @current_resource.version.should == nil end end describe "candidate_version" do it "should return the candidate_version variable if already setup" do @provider.candidate_version = "2.1.1" @provider.should_not_receive(:shell_out!) @provider.candidate_version end it "should lookup the candidate_version if the variable is not already set" do search = mock() search.should_receive(:each_line). and_yield("something-varnish-1.1.1 something varnish like\n"). and_yield("varnish-2.3.4 actual varnish\n") @shell_out = mock('shell_out!', :stdout => search) @provider.should_receive(:shell_out!).with('/opt/local/bin/pkgin se varnish', :env => nil, :returns => [0,1]).and_return(@shell_out) @provider.candidate_version.should == "2.3.4" end end describe "when manipulating a resource" do it "run pkgin and install the package" do out = OpenStruct.new(:stdout => nil) @provider.should_receive(:shell_out!).with("/opt/local/sbin/pkg_info -E \"varnish*\"", {:env => nil, :returns=>[0,1]}).and_return(@shell_out) @provider.should_receive(:shell_out!).with("/opt/local/bin/pkgin -y install varnish-2.1.5nb2", {:env=>nil}).and_return(out) @provider.load_current_resource @provider.install_package("varnish", "2.1.5nb2") end end end chef-11.8.2/spec/unit/provider/package/solaris_spec.rb0000644000004100000410000001636412254362222022723 0ustar www-datawww-data# # Author:: Toomas Pelberg () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Package::Solaris do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Package.new("SUNWbash") @new_resource.source("/tmp/bash.pkg") @provider = Chef::Provider::Package::Solaris.new(@new_resource, @run_context) ::File.stub!(:exists?).and_return(true) end describe "assessing the current package status" do before do @pkginfo =<<-PKGINFO PKGINST: SUNWbash NAME: GNU Bourne-Again shell (bash) CATEGORY: system ARCH: sparc VERSION: 11.10.0,REV=2005.01.08.05.16 BASEDIR: / VENDOR: Sun Microsystems, Inc. DESC: GNU Bourne-Again shell (bash) version 3.0 PSTAMP: sfw10-patch20070430084444 INSTDATE: Nov 04 2009 01:02 HOTLINE: Please contact your local service provider PKGINFO @status = mock("Status", :exitstatus => 0) end it "should create a current resource with the name of new_resource" do @provider.stub!(:popen4).and_return(@status) @provider.load_current_resource @provider.current_resource.name.should == "SUNWbash" end it "should set the current reource package name to the new resource package name" do @provider.stub!(:popen4).and_return(@status) @provider.load_current_resource @provider.current_resource.package_name.should == "SUNWbash" end it "should raise an exception if a source is supplied but not found" do @provider.stub!(:popen4).and_return(@status) ::File.stub!(:exists?).and_return(false) @provider.define_resource_requirements @provider.load_current_resource lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Package) end it "should get the source package version from pkginfo if provided" do @stdout = StringIO.new(@pkginfo) @stdin, @stderr = StringIO.new, StringIO.new @provider.should_receive(:popen4).with("pkginfo -l -d /tmp/bash.pkg SUNWbash").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.should_receive(:popen4).with("pkginfo -l SUNWbash").and_return(@status) @provider.load_current_resource @provider.current_resource.package_name.should == "SUNWbash" @new_resource.version.should == "11.10.0,REV=2005.01.08.05.16" end it "should return the current version installed if found by pkginfo" do @stdout = StringIO.new(@pkginfo) @stdin, @stderr = StringIO.new, StringIO.new @provider.should_receive(:popen4).with("pkginfo -l -d /tmp/bash.pkg SUNWbash").and_return(@status) @provider.should_receive(:popen4).with("pkginfo -l SUNWbash").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.load_current_resource @provider.current_resource.version.should == "11.10.0,REV=2005.01.08.05.16" end it "should raise an exception if the source is not set but we are installing" do @new_resource = Chef::Resource::Package.new("SUNWbash") @provider = Chef::Provider::Package::Solaris.new(@new_resource, @run_context) @provider.stub!(:popen4).and_return(@status) lambda { @provider.run_action(:install) }.should raise_error(Chef::Exceptions::Package) end it "should raise an exception if pkginfo fails to run" do @status = mock("Status", :exitstatus => -1) @provider.stub!(:popen4).and_return(@status) lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package) end it "should return a current resource with a nil version if the package is not found" do @stdout = StringIO.new @provider.should_receive(:popen4).with("pkginfo -l -d /tmp/bash.pkg SUNWbash").and_return(@status) @provider.should_receive(:popen4).with("pkginfo -l SUNWbash").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) @provider.load_current_resource @provider.current_resource.version.should be_nil end end describe "candidate_version" do it "should return the candidate_version variable if already setup" do @provider.candidate_version = "11.10.0,REV=2005.01.08.05.16" @provider.should_not_receive(:popen4) @provider.candidate_version end it "should lookup the candidate_version if the variable is not already set" do @status = mock("Status", :exitstatus => 0) @provider.stub!(:popen4).and_return(@status) @provider.should_receive(:popen4) @provider.candidate_version end it "should throw and exception if the exitstatus is not 0" do @status = mock("Status", :exitstatus => 1) @provider.stub!(:popen4).and_return(@status) lambda { @provider.candidate_version }.should raise_error(Chef::Exceptions::Package) end end describe "install and upgrade" do it "should run pkgadd -n -d with the package source to install" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "pkgadd -n -d /tmp/bash.pkg all" }) @provider.install_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16") end it "should run pkgadd -n -d when the package is a path to install" do @new_resource = Chef::Resource::Package.new("/tmp/bash.pkg") @provider = Chef::Provider::Package::Solaris.new(@new_resource, @run_context) @new_resource.source.should == "/tmp/bash.pkg" @provider.should_receive(:run_command_with_systems_locale).with({ :command => "pkgadd -n -d /tmp/bash.pkg all" }) @provider.install_package("/tmp/bash.pkg", "11.10.0,REV=2005.01.08.05.16") end it "should run pkgadd -n -a /tmp/myadmin -d with the package options -a /tmp/myadmin" do @new_resource.stub!(:options).and_return("-a /tmp/myadmin") @provider.should_receive(:run_command_with_systems_locale).with({ :command => "pkgadd -n -a /tmp/myadmin -d /tmp/bash.pkg all" }) @provider.install_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16") end end describe "remove" do it "should run pkgrm -n to remove the package" do @provider.should_receive(:run_command_with_systems_locale).with({ :command => "pkgrm -n SUNWbash" }) @provider.remove_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16") end it "should run pkgrm -n -a /tmp/myadmin with options -a /tmp/myadmin" do @new_resource.stub!(:options).and_return("-a /tmp/myadmin") @provider.should_receive(:run_command_with_systems_locale).with({ :command => "pkgrm -n -a /tmp/myadmin SUNWbash" }) @provider.remove_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16") end end end chef-11.8.2/spec/unit/provider/package/macports_spec.rb0000644000004100000410000002041612254362222023070 0ustar www-datawww-data# # Author:: David Balatero () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::Package::Macports do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Package.new("zsh") @current_resource = Chef::Resource::Package.new("zsh") @provider = Chef::Provider::Package::Macports.new(@new_resource, @run_context) Chef::Resource::Package.stub!(:new).and_return(@current_resource) @status = mock("Status", :exitstatus => 0) @stdin = StringIO.new @stdout = StringIO.new @stderr = StringIO.new @pid = 2342 end describe "load_current_resource" do it "should create a current resource with the name of the new_resource" do @provider.should_receive(:current_installed_version).and_return(nil) @provider.should_receive(:macports_candidate_version).and_return("4.2.7") @provider.load_current_resource @provider.current_resource.name.should == "zsh" end it "should create a current resource with the version if the package is installed" do @provider.should_receive(:macports_candidate_version).and_return("4.2.7") @provider.should_receive(:current_installed_version).and_return("4.2.7") @provider.load_current_resource @provider.candidate_version.should == "4.2.7" end it "should create a current resource with a nil version if the package is not installed" do @provider.should_receive(:current_installed_version).and_return(nil) @provider.should_receive(:macports_candidate_version).and_return("4.2.7") @provider.load_current_resource @provider.current_resource.version.should be_nil end it "should set a candidate version if one exists" do @provider.should_receive(:current_installed_version).and_return(nil) @provider.should_receive(:macports_candidate_version).and_return("4.2.7") @provider.load_current_resource @provider.candidate_version.should == "4.2.7" end end describe "current_installed_version" do it "should return the current version if the package is installed" do @stdout.should_receive(:read).and_return(< "port install zsh @4.2.7") @provider.install_package("zsh", "4.2.7") end it "should not do anything if a package already exists with the same version" do @current_resource.should_receive(:version).and_return("4.2.7") @provider.current_resource = @current_resource @provider.should_not_receive(:run_command_with_systems_locale) @provider.install_package("zsh", "4.2.7") end it "should add options to the port command when specified" do @current_resource.should_receive(:version).and_return("4.1.6") @provider.current_resource = @current_resource @new_resource.stub!(:options).and_return("-f") @provider.should_receive(:run_command_with_systems_locale).with(:command => "port -f install zsh @4.2.7") @provider.install_package("zsh", "4.2.7") end end describe "purge_package" do it "should run the port uninstall command with the correct version" do @provider.should_receive(:run_command_with_systems_locale).with(:command => "port uninstall zsh @4.2.7") @provider.purge_package("zsh", "4.2.7") end it "should purge the currently active version if no explicit version is passed in" do @provider.should_receive(:run_command_with_systems_locale).with(:command => "port uninstall zsh") @provider.purge_package("zsh", nil) end it "should add options to the port command when specified" do @new_resource.stub!(:options).and_return("-f") @provider.should_receive(:run_command_with_systems_locale).with(:command => "port -f uninstall zsh @4.2.7") @provider.purge_package("zsh", "4.2.7") end end describe "remove_package" do it "should run the port deactivate command with the correct version" do @provider.should_receive(:run_command_with_systems_locale).with(:command => "port deactivate zsh @4.2.7") @provider.remove_package("zsh", "4.2.7") end it "should remove the currently active version if no explicit version is passed in" do @provider.should_receive(:run_command_with_systems_locale).with(:command => "port deactivate zsh") @provider.remove_package("zsh", nil) end it "should add options to the port command when specified" do @new_resource.stub!(:options).and_return("-f") @provider.should_receive(:run_command_with_systems_locale).with(:command => "port -f deactivate zsh @4.2.7") @provider.remove_package("zsh", "4.2.7") end end describe "upgrade_package" do it "should run the port upgrade command with the correct version" do @current_resource.should_receive(:version).at_least(:once).and_return("4.1.6") @provider.current_resource = @current_resource @provider.should_receive(:run_command_with_systems_locale).with(:command => "port upgrade zsh @4.2.7") @provider.upgrade_package("zsh", "4.2.7") end it "should not run the port upgrade command if the version is already installed" do @current_resource.should_receive(:version).at_least(:once).and_return("4.2.7") @provider.current_resource = @current_resource @provider.should_not_receive(:run_command_with_systems_locale) @provider.upgrade_package("zsh", "4.2.7") end it "should call install_package if the package isn't currently installed" do @current_resource.should_receive(:version).at_least(:once).and_return(nil) @provider.current_resource = @current_resource @provider.should_receive(:install_package).and_return(true) @provider.upgrade_package("zsh", "4.2.7") end it "should add options to the port command when specified" do @new_resource.stub!(:options).and_return("-f") @current_resource.should_receive(:version).at_least(:once).and_return("4.1.6") @provider.current_resource = @current_resource @provider.should_receive(:run_command_with_systems_locale).with(:command => "port -f upgrade zsh @4.2.7") @provider.upgrade_package("zsh", "4.2.7") end end end chef-11.8.2/spec/unit/provider/template_spec.rb0000644000004100000410000000555112254362222021463 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2008-2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'stringio' require 'spec_helper' require 'etc' require 'ostruct' require 'support/shared/unit/provider/file' describe Chef::Provider::Template do let(:node) { double('Chef::Node') } let(:events) { double('Chef::Events').as_null_object } # mock all the methods let(:run_context) { double('Chef::RunContext', :node => node, :events => events) } let(:enclosing_directory) { canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates"))) } let(:resource_path) { canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt"))) } # Subject let(:provider) do provider = described_class.new(resource, run_context) provider.stub!(:content).and_return(content) provider end let(:resource) do resource = Chef::Resource::Template.new("seattle", @run_context) resource.path(resource_path) resource end let(:content) do content = mock('Chef::Provider::File::Content::Template', :template_location => "/foo/bar/baz") File.stub(:exists?).with("/foo/bar/baz").and_return(true) content end it_behaves_like Chef::Provider::File context "when creating the template" do let(:node) { double('Chef::Node') } let(:events) { double('Chef::Events').as_null_object } # mock all the methods let(:run_context) { double('Chef::RunContext', :node => node, :events => events) } let(:enclosing_directory) { canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates"))) } let(:resource_path) { canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt"))) } # Subject let(:provider) do provider = described_class.new(resource, run_context) provider.stub!(:content).and_return(content) provider end it "stops executing when the local template source can't be found" do setup_normal_file content.stub!(:template_location).and_return("/baz/bar/foo") File.stub(:exists?).with("/baz/bar/foo").and_return(false) lambda { provider.run_action(:create) }.should raise_error Chef::Mixin::WhyRun::ResourceRequirements::Assertion::AssertionFailure end end end chef-11.8.2/spec/unit/provider/http_request_spec.rb0000644000004100000410000001124412254362222022373 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::HttpRequest do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::HttpRequest.new('adam') @new_resource.name "adam" @new_resource.url "http://www.opscode.com/" @new_resource.message "is cool" @provider = Chef::Provider::HttpRequest.new(@new_resource, @run_context) end describe "load_current_resource" do it "should set up a Chef::REST client, with no authentication" do Chef::HTTP::Simple.should_receive(:new).with(@new_resource.url) @provider.load_current_resource end end describe "when making REST calls" do before(:each) do # run_action(x) forces load_current_resource to run; # that would overwrite our supplied mock Chef::Rest # object @provider.stub!(:load_current_resource).and_return(true) @http = mock("Chef::REST") @provider.http = @http end describe "action_get" do it "should inflate a message block at runtime" do @new_resource.message { "return" } @http.should_receive(:get).with("http://www.opscode.com/?message=return", {}) @provider.run_action(:get) @new_resource.should be_updated end it "should run a GET request" do @http.should_receive(:get).with("http://www.opscode.com/?message=is cool", {}) @provider.run_action(:get) @new_resource.should be_updated end end describe "action_put" do it "should run a PUT request with the message as the payload" do @http.should_receive(:put).with("http://www.opscode.com/", @new_resource.message, {}) @provider.run_action(:put) @new_resource.should be_updated end it "should inflate a message block at runtime" do @new_resource.stub!(:message).and_return(lambda { "return" }) @http.should_receive(:put).with("http://www.opscode.com/", "return", {}) @provider.run_action(:put) @new_resource.should be_updated end end describe "action_post" do it "should run a PUT request with the message as the payload" do @http.should_receive(:post).with("http://www.opscode.com/", @new_resource.message, {}) @provider.run_action(:post) @new_resource.should be_updated end it "should inflate a message block at runtime" do @new_resource.message { "return" } @http.should_receive(:post).with("http://www.opscode.com/", "return", {}) @provider.run_action(:post) @new_resource.should be_updated end end describe "action_delete" do it "should run a DELETE request" do @http.should_receive(:delete).with("http://www.opscode.com/", {}) @provider.run_action(:delete) @new_resource.should be_updated end end describe "action_head" do before do @provider.http = @http end it "should inflate a message block at runtime" do @new_resource.message { "return" } @http.should_receive(:head).with("http://www.opscode.com/?message=return", {}).and_return("") @provider.run_action(:head) @new_resource.should be_updated end it "should run a HEAD request" do @http.should_receive(:head).with("http://www.opscode.com/?message=is cool", {}).and_return("") @provider.run_action(:head) @new_resource.should be_updated end it "should run a HEAD request with If-Modified-Since header" do @new_resource.headers "If-Modified-Since" => File.mtime(__FILE__).httpdate @http.should_receive(:head).with("http://www.opscode.com/?message=is cool", @new_resource.headers) @provider.run_action(:head) end it "doesn't call converge_by if HEAD does not return modified" do @http.should_receive(:head).and_return(false) @provider.should_not_receive(:converge_by) @provider.run_action(:head) end end end end chef-11.8.2/spec/unit/provider/ohai_spec.rb0000644000004100000410000000550512254362222020567 0ustar www-datawww-data# # Author:: Michael Leinartas () # Copyright:: Copyright (c) 2010 Michael Leinartas # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/run_context' describe Chef::Provider::Ohai do before(:each) do # Copied from client_spec @fqdn = "hostname.domainname" @hostname = "hostname" @platform = "example-platform" @platform_version = "example-platform" Chef::Config[:node_name] = @fqdn mock_ohai = { :fqdn => @fqdn, :hostname => @hostname, :platform => @platform, :platform_version => @platform_version, :data => { :origdata => "somevalue" }, :data2 => { :origdata => "somevalue", :newdata => "somevalue" } } mock_ohai.stub!(:all_plugins).and_return(true) mock_ohai.stub!(:require_plugin).and_return(true) mock_ohai.stub!(:data).and_return(mock_ohai[:data], mock_ohai[:data2]) Ohai::System.stub!(:new).and_return(mock_ohai) Chef::Platform.stub!(:find_platform_and_version).and_return({ "platform" => @platform, "platform_version" => @platform_version}) # Fake node with a dummy save @node = Chef::Node.new @node.name(@fqdn) @node.stub!(:save).and_return(@node) @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::Ohai.new("ohai_reload") ohai = Ohai::System.new ohai.all_plugins @node.consume_external_attrs(ohai.data,{}) @provider = Chef::Provider::Ohai.new(@new_resource, @run_context) end describe "when reloading ohai" do before do @node.automatic_attrs[:origdata] = 'somevalue' end it "applies updated ohai data to the node" do @node[:origdata].should == 'somevalue' @node[:newdata].should be_nil @provider.run_action(:reload) @node[:origdata].should == 'somevalue' @node[:newdata].should == 'somevalue' end it "should reload a specific plugin and cause node to pick up new values" do @new_resource.plugin "someplugin" @provider.run_action(:reload) @node[:origdata].should == 'somevalue' @node[:newdata].should == 'somevalue' end end end chef-11.8.2/spec/unit/provider/powershell_spec.rb0000644000004100000410000000237112254362222022031 0ustar www-datawww-data# # Author:: Adam Edwards () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::PowershellScript, "action_run" do before(:each) do @node = Chef::Node.new @node.default["kernel"] = Hash.new @node.default["kernel"][:machine] = :x86_64.to_s @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::PowershellScript.new('run some powershell code', @run_context) @provider = Chef::Provider::PowershellScript.new(@new_resource, @run_context) end it "should set the -File flag as the last flag" do @provider.flags.split(' ').pop.should == "-File" end end chef-11.8.2/spec/unit/provider/ruby_block_spec.rb0000644000004100000410000000311312254362222021773 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2009 Opscode # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Provider::RubyBlock, "initialize" do before(:each) do $evil_global_evil_laugh = :wahwah @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::RubyBlock.new("bloc party") @new_resource.block { $evil_global_evil_laugh = :mwahahaha} @provider = Chef::Provider::RubyBlock.new(@new_resource, @run_context) end it "should call the block and flag the resource as updated" do @provider.run_action(:run) $evil_global_evil_laugh.should == :mwahahaha @new_resource.should be_updated end it "accepts `create' as an alias for `run'" do # SEE ALSO: CHEF-3500 # "create" used to be the default action, it was renamed. @provider.run_action(:create) $evil_global_evil_laugh.should == :mwahahaha @new_resource.should be_updated end end chef-11.8.2/spec/unit/role_spec.rb0000644000004100000410000003205612254362222016757 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/role' describe Chef::Role do before(:each) do @role = Chef::Role.new @role.name("ops_master") end it "has a name" do @role.name("ops_master").should == "ops_master" end it "does not accept a name with spaces" do lambda { @role.name "ops master" }.should raise_error(ArgumentError) end it "does not accept non-String objects for the name" do lambda { @role.name({}) }.should raise_error(ArgumentError) end describe "when a run list is set" do before do @role.run_list(%w{ nginx recipe[ree] role[base]}) end it "returns the run list" do @role.run_list.should == %w{ nginx recipe[ree] role[base]} end describe "and per-environment run lists are set" do before do @role.name("base") @role.run_list(%w{ recipe[nagios::client] recipe[tims-acl::bork]}) @role.env_run_list["prod"] = Chef::RunList.new(*(@role.run_list.to_a << "recipe[prod-base]")) @role.env_run_list["dev"] = Chef::RunList.new end it "uses the default run list as *the* run_list" do @role.run_list.should == Chef::RunList.new("recipe[nagios::client]", "recipe[tims-acl::bork]") end it "gives the default run list as the when getting the _default run list" do @role.run_list_for("_default").should == @role.run_list end it "gives an environment specific run list" do @role.run_list_for("prod").should == Chef::RunList.new("recipe[nagios::client]", "recipe[tims-acl::bork]", "recipe[prod-base]") end it "gives the default run list when no run list exists for the given environment" do @role.run_list_for("qa").should == @role.run_list end it "gives the environment specific run list even if it is empty" do @role.run_list_for("dev").should == Chef::RunList.new end it "env_run_lists can only be set with _default run list in it" do long_exception_name = Chef::Exceptions::InvalidEnvironmentRunListSpecification lambda {@role.env_run_lists({})}.should raise_error(long_exception_name) end end describe "using the old #recipes API" do it "should let you set the recipe array" do @role.recipes([ "one", "two" ]).should == [ "one", "two" ] end it "should let you return the recipe array" do @role.recipes([ "one", "two" ]) @role.recipes.should == [ "one", "two" ] end it "should not list roles in the recipe array" do @role.run_list([ "one", "role[two]"]) @role.recipes.should == [ "recipe[one]", "role[two]" ] end end end describe "default_attributes" do it "should let you set the default attributes hash explicitly" do @role.default_attributes({ :one => 'two' }).should == { :one => 'two' } end it "should let you return the default attributes hash" do @role.default_attributes({ :one => 'two' }) @role.default_attributes.should == { :one => 'two' } end it "should throw an ArgumentError if we aren't a kind of hash" do lambda { @role.default_attributes(Array.new) }.should raise_error(ArgumentError) end end describe "override_attributes" do it "should let you set the override attributes hash explicitly" do @role.override_attributes({ :one => 'two' }).should == { :one => 'two' } end it "should let you return the override attributes hash" do @role.override_attributes({ :one => 'two' }) @role.override_attributes.should == { :one => 'two' } end it "should throw an ArgumentError if we aren't a kind of hash" do lambda { @role.override_attributes(Array.new) }.should raise_error(ArgumentError) end end describe "update_from!" do before(:each) do @role.name('mars_volta') @role.description('Great band!') @role.run_list('one', 'two', 'role[a]') @role.default_attributes({ :el_groupo => 'nuevo' }) @role.override_attributes({ :deloused => 'in the comatorium' }) @example = Chef::Role.new @example.name('newname') @example.description('Really Great band!') @example.run_list('alpha', 'bravo', 'role[alpha]') @example.default_attributes({ :el_groupo => 'nuevo dos' }) @example.override_attributes({ :deloused => 'in the comatorium XOXO' }) end it "should update all fields except for name" do @role.update_from!(@example) @role.name.should == "mars_volta" @role.description.should == @example.description @role.run_list.should == @example.run_list @role.default_attributes.should == @example.default_attributes @role.override_attributes.should == @example.override_attributes end end describe "when serialized as JSON", :json => true do before(:each) do @role.name('mars_volta') @role.description('Great band!') @role.run_list('one', 'two', 'role[a]') @role.default_attributes({ :el_groupo => 'nuevo' }) @role.override_attributes({ :deloused => 'in the comatorium' }) @serialized_role = Chef::JSONCompat.to_json(@role) end it "should serialize to a json hash" do Chef::JSONCompat.to_json(@role).should match(/^\{.+\}$/) end it "includes the name in the JSON output" do @serialized_role.should =~ /"name":"mars_volta"/ end it "includes its description in the JSON" do @serialized_role.should match(/"description":"Great band!"/) end it "should include 'default_attributes'" do @serialized_role.should =~ /"default_attributes":\{"el_groupo":"nuevo"\}/ end it "should include 'override_attributes'" do @serialized_role.should =~ /"override_attributes":\{"deloused":"in the comatorium"\}/ end it "should include 'run_list'" do #Activesupport messes with Chef json formatting #This test should pass with and without activesupport @serialized_role.should =~ /"run_list":\["recipe\[one\]","recipe\[two\]","role\[a\]"\]/ end describe "and it has per-environment run lists" do before do @role.env_run_lists("_default" => ['one', 'two', 'role[a]'], "production" => ['role[monitoring]', 'role[auditing]', 'role[apache]'], "dev" => ["role[nginx]"]) @serialized_role = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(@role), :create_additions => false) end it "includes the per-environment run lists" do #Activesupport messes with Chef json formatting #This test should pass with and without activesupport @serialized_role["env_run_lists"]["production"].should == ['role[monitoring]', 'role[auditing]', 'role[apache]'] @serialized_role["env_run_lists"]["dev"].should == ["role[nginx]"] end it "does not include the default environment in the per-environment run lists" do @serialized_role["env_run_lists"].should_not have_key("_default") end end end describe "when created from JSON", :json => true do before(:each) do @role.name('mars_volta') @role.description('Great band!') @role.run_list('one', 'two', 'role[a]') @role.default_attributes({ 'el_groupo' => 'nuevo' }) @role.override_attributes({ 'deloused' => 'in the comatorium' }) @deserial = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(@role)) end it "should deserialize to a Chef::Role object" do @deserial.should be_a_kind_of(Chef::Role) end %w{ name description default_attributes override_attributes run_list }.each do |t| it "should preserves the '#{t}' attribute from the JSON object" do @deserial.send(t.to_sym).should == @role.send(t.to_sym) end end end ROLE_DSL=<<-EOR name "ceiling_cat" description "like Aliens, but furry" EOR describe "when loading from disk" do it "should return a Chef::Role object from JSON" do File.should_receive(:exists?).with(File.join(Chef::Config[:role_path], 'lolcat.json')).exactly(1).times.and_return(true) IO.should_receive(:read).with(File.join(Chef::Config[:role_path], 'lolcat.json')).and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }') @role.should be_a_kind_of(Chef::Role) @role.class.from_disk("lolcat") end it "should return a Chef::Role object from a Ruby DSL" do File.should_receive(:exists?).with(File.join(Chef::Config[:role_path], 'lolcat.json')).exactly(1).times.and_return(false) File.should_receive(:exists?).with(File.join(Chef::Config[:role_path], 'lolcat.rb')).exactly(2).times.and_return(true) File.should_receive(:readable?).with(File.join(Chef::Config[:role_path], 'lolcat.rb')).exactly(1).times.and_return(true) IO.should_receive(:read).with(File.join(Chef::Config[:role_path], 'lolcat.rb')).and_return(ROLE_DSL) @role.should be_a_kind_of(Chef::Role) @role.class.from_disk("lolcat") end it "should raise an exception if the file does not exist" do File.should_receive(:exists?).with(File.join(Chef::Config[:role_path], 'lolcat.json')).exactly(1).times.and_return(false) File.should_receive(:exists?).with(File.join(Chef::Config[:role_path], 'lolcat.rb')).exactly(1).times.and_return(false) lambda {@role.class.from_disk("lolcat")}.should raise_error(Chef::Exceptions::RoleNotFound) end end describe "when loading from disk and role_path is an array" do before(:each) do Chef::Config[:role_path] = ['/path1', '/path/path2'] end it "should return a Chef::Role object from JSON" do File.should_receive(:exists?).with(File.join('/path1', 'lolcat.json')).exactly(1).times.and_return(true) IO.should_receive(:read).with(File.join('/path1', 'lolcat.json')).and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }') @role.should be_a_kind_of(Chef::Role) @role.class.from_disk("lolcat") end it "should return a Chef::Role object from JSON when role is in the second path" do File.should_receive(:exists?).with(File.join('/path1', 'lolcat.json')).exactly(1).times.and_return(false) File.should_receive(:exists?).with(File.join('/path1', 'lolcat.rb')).exactly(1).times.and_return(false) File.should_receive(:exists?).with(File.join('/path/path2', 'lolcat.json')).exactly(1).times.and_return(true) IO.should_receive(:read).with(File.join('/path/path2', 'lolcat.json')).and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }') @role.should be_a_kind_of(Chef::Role) @role.class.from_disk("lolcat") end it "should return a Chef::Role object from a Ruby DSL" do File.should_receive(:exists?).with(File.join('/path1', 'lolcat.json')).exactly(1).times.and_return(false) File.should_receive(:exists?).with(File.join('/path1', 'lolcat.rb')).exactly(2).times.and_return(true) File.should_receive(:readable?).with(File.join('/path1', 'lolcat.rb')).exactly(1).times.and_return(true) IO.should_receive(:read).with(File.join('/path1', 'lolcat.rb')).and_return(ROLE_DSL) @role.should be_a_kind_of(Chef::Role) @role.class.from_disk("lolcat") end it "should return a Chef::Role object from a Ruby DSL when role is in the second path" do File.should_receive(:exists?).with(File.join('/path1', 'lolcat.json')).exactly(1).times.and_return(false) File.should_receive(:exists?).with(File.join('/path1', 'lolcat.rb')).exactly(1).times.and_return(false) File.should_receive(:exists?).with(File.join('/path/path2', 'lolcat.json')).exactly(1).times.and_return(false) File.should_receive(:exists?).with(File.join('/path/path2', 'lolcat.rb')).exactly(2).times.and_return(true) File.should_receive(:readable?).with(File.join('/path/path2', 'lolcat.rb')).exactly(1).times.and_return(true) IO.should_receive(:read).with(File.join('/path/path2', 'lolcat.rb')).and_return(ROLE_DSL) @role.should be_a_kind_of(Chef::Role) @role.class.from_disk("lolcat") end it "should raise an exception if the file does not exist" do File.should_receive(:exists?).with(File.join('/path1', 'lolcat.json')).exactly(1).times.and_return(false) File.should_receive(:exists?).with(File.join('/path1', 'lolcat.rb')).exactly(1).times.and_return(false) File.should_receive(:exists?).with(File.join('/path/path2', 'lolcat.json')).exactly(1).times.and_return(false) File.should_receive(:exists?).with(File.join('/path/path2', 'lolcat.rb')).exactly(1).times.and_return(false) lambda {@role.class.from_disk("lolcat")}.should raise_error(Chef::Exceptions::RoleNotFound) end end end chef-11.8.2/spec/unit/formatters/0000755000004100000410000000000012254362222016637 5ustar www-datawww-datachef-11.8.2/spec/unit/formatters/error_inspectors/0000755000004100000410000000000012254362222022241 5ustar www-datawww-datachef-11.8.2/spec/unit/formatters/error_inspectors/node_load_error_inspector_spec.rb0000644000004100000410000000164112254362222031025 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' # spec_helper loads the shared examples already. #require 'support/shared/unit/api_error_inspector_spec' describe Chef::Formatters::ErrorInspectors::NodeLoadErrorInspector do it_behaves_like "an api error inspector" end chef-11.8.2/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb0000644000004100000410000002541012254362222030531 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' BAD_RECIPE=<<-E # # Cookbook Name:: syntax-err # Recipe:: default # # Copyright 2012, YOUR_COMPANY_NAME # # All rights reserved - Do Not Redistribute # file "/tmp/explode-me" do mode 0655 owner "root" this_is_not_a_valid_method end E describe Chef::Formatters::ErrorInspectors::CompileErrorInspector do before do @node_name = "test-node.example.com" @description = Chef::Formatters::ErrorDescription.new("Error Evaluating File:") @exception = NoMethodError.new("undefined method `this_is_not_a_valid_method' for Chef::Resource::File") @outputter = Chef::Formatters::Outputter.new(StringIO.new, STDERR) #@outputter = Chef::Formatters::Outputter.new(STDOUT, STDERR) end describe "when scrubbing backtraces" do it "shows backtrace lines from cookbook files" do # Error inspector originally used file_cache_path which is incorrect on # chef-solo. Using cookbook_path should do the right thing for client and # solo. Chef::Config.stub!(:cookbook_path).and_return([ "/home/someuser/dev-laptop/cookbooks" ]) @trace = [ "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'", "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'", "/home/someuser/.multiruby/gems/chef/lib/chef/client.rb:123:in `run'" ] @exception.set_backtrace(@trace) @path = "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb" @inspector = described_class.new(@path, @exception) @expected_filtered_trace = [ "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'", "/home/someuser/dev-laptop/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'", ] @inspector.filtered_bt.should == @expected_filtered_trace end end describe "when explaining an error in the compile phase" do before do Chef::Config.stub!(:cookbook_path).and_return([ "/var/chef/cache/cookbooks" ]) recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" } IO.should_receive(:readlines).with("/var/chef/cache/cookbooks/syntax-err/recipes/default.rb").and_return(recipe_lines) @trace = [ "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'", "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'", "/usr/local/lib/ruby/gems/chef/lib/chef/client.rb:123:in `run'" # should not display ] @exception.set_backtrace(@trace) @path = "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb" @inspector = described_class.new(@path, @exception) @inspector.add_explanation(@description) end it "finds the line number of the error from the stacktrace" do @inspector.culprit_line.should == 14 end it "prints a pretty message" do @description.display(@outputter) end end describe "when explaining an error on windows" do before do Chef::Config.stub!(:cookbook_path).and_return([ "C:/opscode/chef/var/cache/cookbooks" ]) recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" } IO.should_receive(:readlines).at_least(1).times.with(/:\/opscode\/chef\/var\/cache\/cookbooks\/foo\/recipes\/default.rb/).and_return(recipe_lines) @trace = [ "C:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb:14 in `from_file'", "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:144:in `rescue in block in load_libraries'", "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:138:in `block in load_libraries'", "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:230:in `call'", "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:230:in `block (2 levels) in foreach_cookbook_load_segment'", "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:229:in `each'", "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:229:in `block in foreach_cookbook_load_segment'", "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `each'", "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `foreach_cookbook_load_segment'", "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:137:in `load_libraries'", "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:62:in `load'", "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:198:in `setup_run_context'", "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:418:in `do_run'", "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:176:in `run'", "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:283:in `block in run_application'", "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:270:in `loop'", "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:270:in `run_application'", "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application.rb:70:in `run'", "C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/bin/chef-client:26:in `'", "C:/opscode/chef/bin/chef-client:19:in `load'", "C:/opscode/chef/bin/chef-client:19:in `
'" ] @exception.set_backtrace(@trace) @path = "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb" @inspector = described_class.new(@path, @exception) @inspector.add_explanation(@description) end describe "and examining the stack trace for a recipe" do it "find the culprit recipe name when the drive letter is upper case" do @inspector.culprit_file.should == "C:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb" end it "find the culprit recipe name when the drive letter is lower case" do @trace.each { |line| line.gsub!(/^C:/, "c:") } @exception.set_backtrace(@trace) @inspector = described_class.new(@path, @exception) @inspector.add_explanation(@description) @inspector.culprit_file.should == "c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb" end end it "finds the line number of the error from the stack trace" do @inspector.culprit_line.should == 14 end it "prints a pretty message" do @description.display(@outputter) end end describe "when explaining an error on windows, and the backtrace lowercases the drive letter" do before do Chef::Config.stub!(:cookbook_path).and_return([ "C:/opscode/chef/var/cache/cookbooks" ]) recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" } IO.should_receive(:readlines).with("c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb").and_return(recipe_lines) @trace = [ "c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb:14 in `from_file'", "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:144:in `rescue in block in load_libraries'", "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:138:in `block in load_libraries'", "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:230:in `call'", "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:230:in `block (2 levels) in foreach_cookbook_load_segment'", "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:229:in `each'", "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:229:in `block in foreach_cookbook_load_segment'", "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `each'", "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:227:in `foreach_cookbook_load_segment'", "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:137:in `load_libraries'", "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/run_context.rb:62:in `load'", "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:198:in `setup_run_context'", "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:418:in `do_run'", "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/client.rb:176:in `run'", "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:283:in `block in run_application'", "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:270:in `loop'", "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application/client.rb:270:in `run_application'", "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/lib/chef/application.rb:70:in `run'", "c:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-10.14.0/bin/chef-client:26:in `'", "c:/opscode/chef/bin/chef-client:19:in `load'", "c:/opscode/chef/bin/chef-client:19:in `
'" ] @exception.set_backtrace(@trace) @path = "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb" @inspector = described_class.new(@path, @exception) @inspector.add_explanation(@description) end it "finds the culprit recipe name from the stacktrace" do @inspector.culprit_file.should == "c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb" end it "finds the line number of the error from the stack trace" do @inspector.culprit_line.should == 14 end it "prints a pretty message" do @description.display(@outputter) end end end chef-11.8.2/spec/unit/formatters/error_inspectors/cookbook_resolve_error_inspector_spec.rb0000644000004100000410000001262512254362222032452 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector do before do @expanded_run_list = Chef::RunList.new("recipe[annoyances]", "recipe[apache2]", "recipe[users]", "recipe[chef::client]") @description = Chef::Formatters::ErrorDescription.new("Error Resolving Cookbooks for Run List:") @outputter_output = StringIO.new @outputter = Chef::Formatters::Outputter.new(@outputter_output, STDERR) # @outputter = Chef::Formatters::Outputter.new(STDOUT, STDERR) end describe "when explaining a 403 error" do before do @response_body = %Q({"error": [{"message": "gtfo"}]) @response = Net::HTTPForbidden.new("1.1", "403", "(response) forbidden") @response.stub!(:body).and_return(@response_body) @exception = Net::HTTPServerException.new("(exception) forbidden", @response) @inspector = Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector.new(@expanded_run_list, @exception) @inspector.add_explanation(@description) end it "prints a nice message" do lambda { @description.display(@outputter) }.should_not raise_error end end describe "when explaining a PreconditionFailed (412) error with current error message style" do # Chef currently returns error messages with some fields as JSON strings, # which must be re-parsed to get the actual data. before do @response_body = "{\"error\":[\"{\\\"non_existent_cookbooks\\\":[\\\"apache2\\\"],\\\"cookbooks_with_no_versions\\\":[\\\"users\\\"],\\\"message\\\":\\\"Run list contains invalid items: no such cookbook nope.\\\"}\"]}" @response = Net::HTTPPreconditionFailed.new("1.1", "412", "(response) unauthorized") @response.stub!(:body).and_return(@response_body) @exception = Net::HTTPServerException.new("(exception) precondition failed", @response) @inspector = Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector.new(@expanded_run_list, @exception) @inspector.add_explanation(@description) end it "prints a pretty message" do @description.display(@outputter) @outputter_output.rewind observed_output = @outputter_output.read observed_output.should include("apache2") observed_output.should include("users") observed_output.should_not include("Run list contains invalid items: no such cookbook nope.") end end describe "when explaining a PreconditionFailed (412) error with current error message style without cookbook details" do # Chef currently returns error messages with some fields as JSON strings, # which must be re-parsed to get the actual data. # In some cases the error message doesn't contain any cookbook # details. But we should still print a pretty error message. before do @response_body = "{\"error\":[{\"non_existent_cookbooks\":[],\"cookbooks_with_no_versions\":[],\"message\":\"unable to solve dependencies in alotted time.\"}]}" @response = Net::HTTPPreconditionFailed.new("1.1", "412", "(response) unauthorized") @response.stub!(:body).and_return(@response_body) @exception = Net::HTTPServerException.new("(exception) precondition failed", @response) @inspector = Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector.new(@expanded_run_list, @exception) @inspector.add_explanation(@description) end it "prints a pretty message" do @description.display(@outputter) @outputter_output.rewind @outputter_output.read.should include("unable to solve dependencies in alotted time.") end end describe "when explaining a PreconditionFailed (412) error with single encoded JSON" do # Chef currently returns error messages with some fields as JSON strings, # which must be re-parsed to get the actual data. before do @response_body = "{\"error\":[{\"non_existent_cookbooks\":[\"apache2\"],\"cookbooks_with_no_versions\":[\"users\"],\"message\":\"Run list contains invalid items: no such cookbook nope.\"}]}" @response = Net::HTTPPreconditionFailed.new("1.1", "412", "(response) unauthorized") @response.stub!(:body).and_return(@response_body) @exception = Net::HTTPServerException.new("(exception) precondition failed", @response) @inspector = Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector.new(@expanded_run_list, @exception) @inspector.add_explanation(@description) end it "prints a pretty message" do @description.display(@outputter) @outputter_output.rewind observed_output = @outputter_output.read observed_output.should include("apache2") observed_output.should include("users") observed_output.should_not include("Run list contains invalid items: no such cookbook nope.") end end end chef-11.8.2/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb0000644000004100000410000001546512254362222031237 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Formatters::ErrorInspectors::ResourceFailureInspector do include Chef::DSL::Recipe def run_context node = Chef::Node.new node.automatic_attrs[:platform] = "ubuntu" node.automatic_attrs[:platform_version] = "10.04" Chef::RunContext.new(node, {}, nil) end def cookbook_name "rspec-example" end before do @description = Chef::Formatters::ErrorDescription.new("Error Converging Resource:") @stdout = StringIO.new @outputter = Chef::Formatters::Outputter.new(@stdout, STDERR) #@outputter = Chef::Formatters::Outputter.new(STDOUT, STDERR) Chef::Config.stub!(:cookbook_path).and_return([ "/var/chef/cache" ]) end describe "when explaining an error converging a resource" do before do source_line = caller(0)[0] @resource = package("non-existing-package") do only_if do true end not_if("/bin/false") action :upgrade end @trace = [ "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'", "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'", "/usr/local/lib/ruby/gems/chef/lib/chef/client.rb:123:in `run'" # should not display ] @exception = Chef::Exceptions::Package.new("No such package 'non-existing-package'") @exception.set_backtrace(@trace) @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception) @inspector.add_explanation(@description) end it "filters chef core code from the backtrace" do @expected_filtered_trace = [ "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb:14:in `from_file'", "/var/chef/cache/cookbooks/syntax-err/recipes/default.rb:11:in `from_file'", ] @inspector.filtered_bt.should == @expected_filtered_trace end it "prints a pretty message" do @description.display(@outputter) end describe "and the error is a template error" do before do @description = Chef::Formatters::ErrorDescription.new("Error Converging Resource:") @template_class = Class.new { include Chef::Mixin::Template } @template = @template_class.new @context = Chef::Mixin::Template::TemplateContext.new({}) @context[:chef] = "cool" @resource = template("/tmp/foo.txt") do mode "0644" end @error = begin @context.render_template_from_string("foo\nbar\nbaz\n<%= this_is_not_defined %>\nquin\nqunx\ndunno") rescue Chef::Mixin::Template::TemplateError => e e end @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @error) @inspector.add_explanation(@description) end it "includes contextual info from the template error in the output" do @description.display(@outputter) @stdout.string.should include(@error.source_listing) end end describe "recipe_snippet" do before do # fake code to run through #recipe_snippet source_file = [ "if true", "var = non_existant", "end" ] IO.stub!(:readlines).and_return(source_file) File.stub!(:exists?).and_return(true) end it "parses a Windows path" do source_line = "C:/Users/btm/chef/chef/spec/unit/fake_file.rb:2: undefined local variable or method `non_existant' for main:Object (NameError)" @resource.source_line = source_line @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception) @inspector.recipe_snippet.should match(/^# In C:\/Users\/btm/) end it "parses a unix path" do source_line = "/home/btm/src/chef/chef/spec/unit/fake_file.rb:2: undefined local variable or method `non_existant' for main:Object (NameError)" @resource.source_line = source_line @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception) @inspector.recipe_snippet.should match(/^# In \/home\/btm/) end context "when the recipe file does not exist" do before do File.stub!(:exists?).and_return(false) IO.stub!(:readlines).and_raise(Errno::ENOENT) end it "does not try to parse a recipe in chef-shell/irb (CHEF-3411)" do @resource.source_line = "(irb#1):1:in `irb_binding'" @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception) @inspector.recipe_snippet.should be_nil end it "does not raise an exception trying to load a non-existant file (CHEF-3411)" do @resource.source_line = "/somewhere/in/space" @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception) lambda { @inspector.recipe_snippet }.should_not raise_error end end end describe "when examining a resource that confuses the parser" do before do angry_bash_recipe = File.expand_path("cookbooks/angrybash/recipes/default.rb", CHEF_SPEC_DATA) source_line = "#{angry_bash_recipe}:1:in `
'" # source_line = caller(0)[0]; @resource = bash "go off the rails" do # code <<-END # for i in localhost 127.0.0.1 #{Socket.gethostname()} # do # echo "grant all on *.* to root@'$i' identified by 'a_password'; flush privileges;" | mysql -u root -h 127.0.0.1 # done # END # end @resource = eval(IO.read(angry_bash_recipe)) @resource.source_line = source_line @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception) @exception.set_backtrace(@trace) @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception) end it "does not generate an error" do lambda { @inspector.add_explanation(@description) }.should_not raise_error(TypeError) @description.display(@outputter) end end end end chef-11.8.2/spec/unit/formatters/error_inspectors/run_list_expansion_error_inspector_spec.rb0000644000004100000410000000644512254362222033033 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector do before do @node = Chef::Node.new.tap do |n| n.name("unit-test.example.com") n.run_list("role[base]") end @description = Chef::Formatters::ErrorDescription.new("Error Expanding RunList:") @outputter = Chef::Formatters::Outputter.new(StringIO.new, STDERR) #@outputter = Chef::Formatters::Outputter.new(STDOUT, STDERR) end describe "when explaining a missing role error" do before do @run_list_expansion = Chef::RunList::RunListExpansion.new("_default", @node.run_list) @run_list_expansion.missing_roles_with_including_role << [ "role[missing-role]", "role[base]" ] @run_list_expansion.missing_roles_with_including_role << [ "role[another-missing-role]", "role[base]" ] @exception = Chef::Exceptions::MissingRole.new(@run_list_expansion) @inspector = Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector.new(@node, @exception) @inspector.add_explanation(@description) end it "prints a pretty message" do @description.display(@outputter) end end describe "when explaining an HTTP 403 error" do before do @response_body = "forbidden" @response = Net::HTTPForbidden.new("1.1", "403", "(response) forbidden") @response.stub!(:body).and_return(@response_body) @exception = Net::HTTPServerException.new("(exception) forbidden", @response) @inspector = Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector.new(@node, @exception) @inspector.stub!(:config).and_return(:node_name => "unit-test.example.com") @inspector.add_explanation(@description) end it "prints a pretty message" do @description.display(@outputter) end end describe "when explaining an HTTP 401 error" do before do @response_body = "check your key and node name" @response = Net::HTTPUnauthorized.new("1.1", "401", "(response) unauthorized") @response.stub!(:body).and_return(@response_body) @exception = Net::HTTPServerException.new("(exception) unauthorized", @response) @inspector = Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector.new(@node, @exception) @inspector.stub!(:config).and_return(:node_name => "unit-test.example.com", :client_key => "/etc/chef/client.pem", :chef_server_url => "http://chef.example.com") @inspector.add_explanation(@description) end it "prints a pretty message" do @description.display(@outputter) end end end chef-11.8.2/spec/unit/formatters/error_inspectors/cookbook_sync_error_inspector_spec.rb0000644000004100000410000000301712254362222031742 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Formatters::ErrorInspectors::CookbookSyncErrorInspector do before do @description = Chef::Formatters::ErrorDescription.new("Error Expanding RunList:") @outputter = Chef::Formatters::Outputter.new(StringIO.new, STDERR) #@outputter = Chef::Formatters::Outputter.new(STDOUT, STDERR) end describe "when explaining a 502 error" do before do @response_body = "sad trombone orchestra" @response = Net::HTTPBadGateway.new("1.1", "502", "(response) bad gateway") @response.stub!(:body).and_return(@response_body) @exception = Net::HTTPFatalError.new("(exception) bad gateway", @response) @inspector = described_class.new({}, @exception) @inspector.add_explanation(@description) end it "prints a nice message" do @description.display(@outputter) end end end chef-11.8.2/spec/unit/formatters/error_inspectors/registration_error_inspector_spec.rb0000644000004100000410000000164512254362222031617 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' # spec_helper loads the shared examples already. #require 'support/shared/unit/api_error_inspector_spec' describe Chef::Formatters::ErrorInspectors::RegistrationErrorInspector do it_behaves_like "an api error inspector" end chef-11.8.2/spec/unit/cookbook_loader_spec.rb0000644000004100000410000001771712254362222021161 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::CookbookLoader do before(:each) do @repo_paths = [ File.expand_path(File.join(CHEF_SPEC_DATA, "kitchen")), File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) ] @cookbook_loader = Chef::CookbookLoader.new(@repo_paths) end describe "loading all cookbooks" do before(:each) do @cookbook_loader.load_cookbooks end describe "[]" do it "should return cookbook objects with []" do @cookbook_loader[:openldap].should be_a_kind_of(Chef::CookbookVersion) end it "should raise an exception if it cannot find a cookbook with []" do lambda { @cookbook_loader[:monkeypoop] }.should raise_error(Chef::Exceptions::CookbookNotFoundInRepo) end it "should allow you to look up available cookbooks with [] and a symbol" do @cookbook_loader[:openldap].name.should eql(:openldap) end it "should allow you to look up available cookbooks with [] and a string" do @cookbook_loader["openldap"].name.should eql(:openldap) end end describe "each" do it "should allow you to iterate over cookbooks with each" do seen = Hash.new @cookbook_loader.each do |cookbook_name, cookbook| seen[cookbook_name] = true end seen.should have_key("openldap") seen.should have_key("apache2") end it "should iterate in alphabetical order" do seen = Array.new @cookbook_loader.each do |cookbook_name, cookbook| seen << cookbook_name end seen[0].should == "angrybash" seen[1].should == "apache2" seen[2].should == "borken" seen[3].should == "ignorken" seen[4].should == "java" seen[5].should == "openldap" end end describe "load_cookbooks" do it "should find all the cookbooks in the cookbook path" do Chef::Config.cookbook_path << File.expand_path(File.join(CHEF_SPEC_DATA, "hidden-cookbooks")) @cookbook_loader.load_cookbooks @cookbook_loader.should have_key(:openldap) @cookbook_loader.should have_key(:apache2) end it "should allow you to override an attribute file via cookbook_path" do @cookbook_loader[:openldap].attribute_filenames.detect { |f| f =~ /cookbooks\/openldap\/attributes\/default.rb/ }.should_not eql(nil) @cookbook_loader[:openldap].attribute_filenames.detect { |f| f =~ /kitchen\/openldap\/attributes\/default.rb/ }.should eql(nil) end it "should load different attribute files from deeper paths" do @cookbook_loader[:openldap].attribute_filenames.detect { |f| f =~ /kitchen\/openldap\/attributes\/robinson.rb/ }.should_not eql(nil) end it "should allow you to override a definition file via cookbook_path" do @cookbook_loader[:openldap].definition_filenames.detect { |f| f =~ /cookbooks\/openldap\/definitions\/client.rb/ }.should_not eql(nil) @cookbook_loader[:openldap].definition_filenames.detect { |f| f =~ /kitchen\/openldap\/definitions\/client.rb/ }.should eql(nil) end it "should load definition files from deeper paths" do @cookbook_loader[:openldap].definition_filenames.detect { |f| f =~ /kitchen\/openldap\/definitions\/drewbarrymore.rb/ }.should_not eql(nil) end it "should allow you to override a recipe file via cookbook_path" do @cookbook_loader[:openldap].recipe_filenames.detect { |f| f =~ /cookbooks\/openldap\/recipes\/gigantor.rb/ }.should_not eql(nil) @cookbook_loader[:openldap].recipe_filenames.detect { |f| f =~ /kitchen\/openldap\/recipes\/gigantor.rb/ }.should eql(nil) end it "should load recipe files from deeper paths" do @cookbook_loader[:openldap].recipe_filenames.detect { |f| f =~ /kitchen\/openldap\/recipes\/woot.rb/ }.should_not eql(nil) end it "should allow you to have an 'ignore' file, which skips loading files in later cookbooks" do @cookbook_loader[:openldap].recipe_filenames.detect { |f| f =~ /kitchen\/openldap\/recipes\/ignoreme.rb/ }.should eql(nil) end it "should find files that start with a ." do @cookbook_loader[:openldap].file_filenames.detect { |f| f =~ /\.dotfile$/ }.should =~ /\.dotfile$/ @cookbook_loader[:openldap].file_filenames.detect { |f| f =~ /\.ssh\/id_rsa$/ }.should =~ /\.ssh\/id_rsa$/ end it "should load the metadata for the cookbook" do @cookbook_loader.metadata[:openldap].name.to_s.should == "openldap" @cookbook_loader.metadata[:openldap].should be_a_kind_of(Chef::Cookbook::Metadata) end it "should check each cookbook directory only once (CHEF-3487)" do cookbooks = [] @repo_paths.each do |repo_path| cookbooks |= Dir[File.join(repo_path, "*")] end cookbooks.each do |cookbook| File.should_receive(:directory?).with(cookbook).once; end @cookbook_loader.load_cookbooks end end # load_cookbooks end # loading all cookbooks describe "loading only one cookbook" do before(:each) do @cookbook_loader = Chef::CookbookLoader.new(@repo_paths) @cookbook_loader.load_cookbook("openldap") end it "should have loaded the correct cookbook" do seen = Hash.new @cookbook_loader.each do |cookbook_name, cookbook| seen[cookbook_name] = true end seen.should have_key("openldap") end it "should not duplicate keys when serialized to JSON" do # Chef JSON serialization will generate duplicate keys if given # a Hash containing matching string and symbol keys. See CHEF-4571. aa = @cookbook_loader["openldap"] aa.to_hash["metadata"].recipes.keys.should_not include(:openldap) aa.to_hash["metadata"].recipes.keys.should include("openldap") expected_desc = "Main Open LDAP configuration" aa.to_hash["metadata"].recipes["openldap"].should == expected_desc raw = aa.to_hash["metadata"].recipes.to_json search_str = "\"openldap\":\"" key_idx = raw.index(search_str) key_idx.should be > 0 dup_idx = raw[(key_idx + 1)..-1].index(search_str) dup_idx.should be_nil end it "should not load the cookbook again when accessed" do @cookbook_loader.should_not_receive('load_cookbook') @cookbook_loader["openldap"] end it "should not load the other cookbooks" do seen = Hash.new @cookbook_loader.each do |cookbook_name, cookbook| seen[cookbook_name] = true end seen.should_not have_key("apache2") end it "should load another cookbook lazily with []" do @cookbook_loader["apache2"].should be_a_kind_of(Chef::CookbookVersion) end describe "loading all cookbooks after loading only one cookbook" do before(:each) do @cookbook_loader.load_cookbooks end it "should load all cookbooks" do seen = Hash.new @cookbook_loader.each do |cookbook_name, cookbook| seen[cookbook_name] = true end seen.should have_key("openldap") seen.should have_key("apache2") end end end # loading only one cookbook end chef-11.8.2/spec/unit/exceptions_spec.rb0000644000004100000410000000714412254362222020177 0ustar www-datawww-data# # Author:: Thomas Bishop () # Author:: Christopher Walters () # Author:: Kyle Goodwin () # Copyright:: Copyright (c) 2010 Thomas Bishop # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Exceptions do exception_to_super_class = { Chef::Exceptions::Application => RuntimeError, Chef::Exceptions::Cron => RuntimeError, Chef::Exceptions::Env => RuntimeError, Chef::Exceptions::Exec => RuntimeError, Chef::Exceptions::FileNotFound => RuntimeError, Chef::Exceptions::Package => RuntimeError, Chef::Exceptions::Service => RuntimeError, Chef::Exceptions::Route => RuntimeError, Chef::Exceptions::SearchIndex => RuntimeError, Chef::Exceptions::Override => RuntimeError, Chef::Exceptions::UnsupportedAction => RuntimeError, Chef::Exceptions::MissingLibrary => RuntimeError, Chef::Exceptions::MissingRole => RuntimeError, Chef::Exceptions::CannotDetermineNodeName => RuntimeError, Chef::Exceptions::User => RuntimeError, Chef::Exceptions::Group => RuntimeError, Chef::Exceptions::Link => RuntimeError, Chef::Exceptions::Mount => RuntimeError, Chef::Exceptions::PrivateKeyMissing => RuntimeError, Chef::Exceptions::CannotWritePrivateKey => RuntimeError, Chef::Exceptions::RoleNotFound => RuntimeError, Chef::Exceptions::ValidationFailed => ArgumentError, Chef::Exceptions::InvalidPrivateKey => ArgumentError, Chef::Exceptions::ConfigurationError => ArgumentError, Chef::Exceptions::RedirectLimitExceeded => RuntimeError, Chef::Exceptions::AmbiguousRunlistSpecification => ArgumentError, Chef::Exceptions::CookbookNotFound => RuntimeError, Chef::Exceptions::AttributeNotFound => RuntimeError, Chef::Exceptions::InvalidCommandOption => RuntimeError, Chef::Exceptions::CommandTimeout => RuntimeError, Mixlib::ShellOut::ShellCommandFailed => RuntimeError, Chef::Exceptions::RequestedUIDUnavailable => RuntimeError, Chef::Exceptions::InvalidHomeDirectory => ArgumentError, Chef::Exceptions::DsclCommandFailed => RuntimeError, Chef::Exceptions::UserIDNotFound => ArgumentError, Chef::Exceptions::GroupIDNotFound => ArgumentError, Chef::Exceptions::InvalidResourceReference => RuntimeError, Chef::Exceptions::ResourceNotFound => RuntimeError, Chef::Exceptions::InvalidResourceSpecification => ArgumentError, Chef::Exceptions::SolrConnectionError => RuntimeError, Chef::Exceptions::InvalidDataBagPath => ArgumentError, Chef::Exceptions::InvalidEnvironmentPath => ArgumentError, Chef::Exceptions::EnvironmentNotFound => RuntimeError, Chef::Exceptions::InvalidVersionConstraint => ArgumentError, Chef::Exceptions::IllegalVersionConstraint => NotImplementedError } exception_to_super_class.each do |exception, expected_super_class| it "should have an exception class of #{exception} which inherits from #{expected_super_class}" do lambda{ raise exception }.should raise_error(expected_super_class) end end end chef-11.8.2/spec/unit/knife/0000755000004100000410000000000012254362222015545 5ustar www-datawww-datachef-11.8.2/spec/unit/knife/cookbook_create_spec.rb0000644000004100000410000002642712254362222022250 0ustar www-datawww-data# # Author:: Nuo Yan () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'tmpdir' describe Chef::Knife::CookbookCreate do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::CookbookCreate.new @knife.config = {} @knife.name_args = ["foobar"] @stdout = StringIO.new @knife.stub!(:stdout).and_return(@stdout) end describe "run" do # Fixes CHEF-2579 it "should expand the path of the cookbook directory" do File.should_receive(:expand_path).with("~/tmp/monkeypants") @knife.config = {:cookbook_path => "~/tmp/monkeypants"} @knife.stub!(:create_cookbook) @knife.stub!(:create_readme) @knife.stub!(:create_changelog) @knife.stub!(:create_metadata) @knife.run end it "should create a new cookbook with default values to copyright name, email, readme format and license if those are not supplied" do @dir = Dir.tmpdir @knife.config = {:cookbook_path => @dir} @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "YOUR_COMPANY_NAME", "none") @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "md") @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "YOUR_COMPANY_NAME", "YOUR_EMAIL", "none", "md") @knife.run end it "should create a new cookbook with specified company name in the copyright section if one is specified" do @dir = Dir.tmpdir @knife.config = { :cookbook_path => @dir, :cookbook_copyright => "Opscode, Inc" } @knife.name_args=["foobar"] @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "none") @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "md") @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "YOUR_EMAIL", "none", "md") @knife.run end it "should create a new cookbook with specified copyright name and email if they are specified" do @dir = Dir.tmpdir @knife.config = { :cookbook_path => @dir, :cookbook_copyright => "Opscode, Inc", :cookbook_email => "nuo@opscode.com" } @knife.name_args=["foobar"] @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "none") @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "md") @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "none", "md") @knife.run end it "should create a new cookbook with specified copyright name and email and license information (true) if they are specified" do @dir = Dir.tmpdir @knife.config = { :cookbook_path => @dir, :cookbook_copyright => "Opscode, Inc", :cookbook_email => "nuo@opscode.com", :cookbook_license => "apachev2" } @knife.name_args=["foobar"] @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "apachev2") @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "md") @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "apachev2", "md") @knife.run end it "should create a new cookbook with specified copyright name and email and license information (false) if they are specified" do @dir = Dir.tmpdir @knife.config = { :cookbook_path => @dir, :cookbook_copyright => "Opscode, Inc", :cookbook_email => "nuo@opscode.com", :cookbook_license => false } @knife.name_args=["foobar"] @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "none") @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "md") @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "none", "md") @knife.run end it "should create a new cookbook with specified copyright name and email and license information ('false' as string) if they are specified" do @dir = Dir.tmpdir @knife.config = { :cookbook_path => @dir, :cookbook_copyright => "Opscode, Inc", :cookbook_email => "nuo@opscode.com", :cookbook_license => "false" } @knife.name_args=["foobar"] @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "none") @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "md") @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "none", "md") @knife.run end it "should allow specifying a gpl2 license" do @dir = Dir.tmpdir @knife.config = { :cookbook_path => @dir, :cookbook_copyright => "Opscode, Inc", :cookbook_email => "nuo@opscode.com", :cookbook_license => "gplv2" } @knife.name_args=["foobar"] @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "gplv2") @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "md") @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "gplv2", "md") @knife.run end it "should allow specifying a gplv3 license" do @dir = Dir.tmpdir @knife.config = { :cookbook_path => @dir, :cookbook_copyright => "Opscode, Inc", :cookbook_email => "nuo@opscode.com", :cookbook_license => "gplv3" } @knife.name_args=["foobar"] @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "gplv3") @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "md") @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "gplv3", "md") @knife.run end it "should allow specifying the mit license" do @dir = Dir.tmpdir @knife.config = { :cookbook_path => @dir, :cookbook_copyright => "Opscode, Inc", :cookbook_email => "nuo@opscode.com", :cookbook_license => "mit" } @knife.name_args=["foobar"] @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit") @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "md") @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "mit", "md") @knife.run end it "should allow specifying the rdoc readme format" do @dir = Dir.tmpdir @knife.config = { :cookbook_path => @dir, :cookbook_copyright => "Opscode, Inc", :cookbook_email => "nuo@opscode.com", :cookbook_license => "mit", :readme_format => "rdoc" } @knife.name_args=["foobar"] @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit") @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "rdoc") @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "mit", "rdoc") @knife.run end it "should allow specifying the mkd readme format" do @dir = Dir.tmpdir @knife.config = { :cookbook_path => @dir, :cookbook_copyright => "Opscode, Inc", :cookbook_email => "nuo@opscode.com", :cookbook_license => "mit", :readme_format => "mkd" } @knife.name_args=["foobar"] @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit") @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "mkd") @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "mit", "mkd") @knife.run end it "should allow specifying the txt readme format" do @dir = Dir.tmpdir @knife.config = { :cookbook_path => @dir, :cookbook_copyright => "Opscode, Inc", :cookbook_email => "nuo@opscode.com", :cookbook_license => "mit", :readme_format => "txt" } @knife.name_args=["foobar"] @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit") @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "txt") @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "mit", "txt") @knife.run end it "should allow specifying an arbitrary readme format" do @dir = Dir.tmpdir @knife.config = { :cookbook_path => @dir, :cookbook_copyright => "Opscode, Inc", :cookbook_email => "nuo@opscode.com", :cookbook_license => "mit", :readme_format => "foo" } @knife.name_args=["foobar"] @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit") @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "foo") @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "mit", "foo") @knife.run end context "when the cookbooks path is set to nil" do before do Chef::Config[:cookbook_path] = nil end it "should throw an argument error" do @dir = Dir.tmpdir lambda{@knife.run}.should raise_error(ArgumentError) end end end end chef-11.8.2/spec/unit/knife/node_from_file_spec.rb0000644000004100000410000000332512254362222022056 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' Chef::Knife::NodeFromFile.load_deps describe Chef::Knife::NodeFromFile do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::NodeFromFile.new @knife.config = { :print_after => nil } @knife.name_args = [ "adam.rb" ] @knife.stub!(:output).and_return(true) @knife.stub!(:confirm).and_return(true) @node = Chef::Node.new() @node.stub!(:save) @knife.loader.stub!(:load_from).and_return(@node) @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) end describe "run" do it "should load from a file" do @knife.loader.should_receive(:load_from).with('nodes', 'adam.rb').and_return(@node) @knife.run end it "should not print the Node" do @knife.should_not_receive(:output) @knife.run end describe "with -p or --print-after" do it "should print the Node" do @knife.config[:print_after] = true @knife.should_receive(:output) @knife.run end end end end chef-11.8.2/spec/unit/knife/client_delete_spec.rb0000644000004100000410000000237012254362222021706 0ustar www-datawww-data# # Author:: Thomas Bishop () # Copyright:: Copyright (c) 2011 Thomas Bishop # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::ClientDelete do before(:each) do @knife = Chef::Knife::ClientDelete.new @knife.name_args = [ 'adam' ] end describe 'run' do it 'should delete the client' do @knife.should_receive(:delete_object).with(Chef::ApiClient, 'adam') @knife.run end it 'should print usage and exit when a client name is not provided' do @knife.name_args = [] @knife.should_receive(:show_usage) @knife.ui.should_receive(:fatal) lambda { @knife.run }.should raise_error(SystemExit) end end end chef-11.8.2/spec/unit/knife/environment_delete_spec.rb0000644000004100000410000000421512254362222022774 0ustar www-datawww-data# # Author:: Stephen Delano () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::EnvironmentDelete do before(:each) do @knife = Chef::Knife::EnvironmentDelete.new @knife.stub!(:msg).and_return true @knife.stub!(:output).and_return true @knife.stub!(:show_usage).and_return true @knife.stub!(:confirm).and_return true @knife.name_args = [ "production" ] @environment = Chef::Environment.new @environment.name("production") @environment.description("Please delete me") @environment.stub!(:destroy).and_return true Chef::Environment.stub!(:load).and_return @environment end it "should confirm that you want to delete" do @knife.should_receive(:confirm) @knife.run end it "should load the environment" do Chef::Environment.should_receive(:load).with("production") @knife.run end it "should delete the environment" do @environment.should_receive(:destroy) @knife.run end it "should not print the environment" do @knife.should_not_receive(:output) @knife.run end it "should show usage and exit when no environment name is provided" do @knife.name_args = [] @knife.ui.should_receive(:fatal) @knife.should_receive(:show_usage) lambda { @knife.run }.should raise_error(SystemExit) end describe "with --print-after" do it "should pretty print the environment, formatted for display" do @knife.config[:print_after] = true @knife.should_receive(:output).with(@environment) @knife.run end end end chef-11.8.2/spec/unit/knife/cookbook_show_spec.rb0000644000004100000410000002066512254362222021763 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, eersion 2.0 # # 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. # # rename to cookbook not coookbook require 'spec_helper' describe Chef::Knife::CookbookShow do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::CookbookShow.new @knife.config = { } @knife.name_args = [ "cookbook_name" ] @rest = mock(Chef::REST) @knife.stub!(:rest).and_return(@rest) @knife.stub!(:pretty_print).and_return(true) @knife.stub!(:output).and_return(true) end describe "run" do describe "with 0 arguments: help" do it 'should should print usage and exit when given no arguments' do @knife.name_args = [] @knife.should_receive(:show_usage) @knife.ui.should_receive(:fatal) lambda { @knife.run }.should raise_error(SystemExit) end end describe "with 1 argument: versions" do before(:each) do @response = { "cookbook_name" => { "url" => "http://url/cookbooks/cookbook_name", "versions" => [ { "version" => "0.10.0", "url" => "http://url/cookbooks/cookbook_name/0.10.0" }, { "version" => "0.9.0", "url" => "http://url/cookbookx/cookbook_name/0.9.0" }, { "version" => "0.8.0", "url" => "http://url/cookbooks/cookbook_name/0.8.0" } ] } } end it "should show the raw cookbook data" do @rest.should_receive(:get_rest).with("cookbooks/cookbook_name").and_return(@response) @knife.should_receive(:format_cookbook_list_for_display).with(@response) @knife.run end it "should respect the user-supplied environment" do @knife.config[:environment] = "foo" @rest.should_receive(:get_rest).with("environments/foo/cookbooks/cookbook_name").and_return(@response) @knife.should_receive(:format_cookbook_list_for_display).with(@response) @knife.run end end describe "with 2 arguments: name and version" do before(:each) do @knife.name_args << "0.1.0" @response = { "0.1.0" => { "recipes" => {"default.rb" => ""} } } end it "should show the specific part of a cookbook" do @rest.should_receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@response) @knife.should_receive(:output).with(@response) @knife.run end end describe "with 3 arguments: name, version, and segment" do before(:each) do @knife.name_args = [ "cookbook_name", "0.1.0", "recipes" ] @cookbook_response = Chef::CookbookVersion.new("cookbook_name") @manifest = { "recipes" => [ { :name => "default.rb", :path => "recipes/default.rb", :checksum => "1234", :url => "http://example.org/files/default.rb" } ] } @cookbook_response.manifest = @manifest @response = {"name"=>"default.rb", "url"=>"http://example.org/files/default.rb", "checksum"=>"1234", "path"=>"recipes/default.rb"} end it "should print the json of the part" do @rest.should_receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response) @knife.should_receive(:output).with(@cookbook_response.manifest["recipes"]) @knife.run end end describe "with 4 arguments: name, version, segment and filename" do before(:each) do @knife.name_args = [ "cookbook_name", "0.1.0", "recipes", "default.rb" ] @cookbook_response = Chef::CookbookVersion.new("cookbook_name") @cookbook_response.manifest = { "recipes" => [ { :name => "default.rb", :path => "recipes/default.rb", :checksum => "1234", :url => "http://example.org/files/default.rb" } ] } @response = "Example recipe text" end it "should print the raw result of the request (likely a file!)" do @rest.should_receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response) @rest.should_receive(:get_rest).with("http://example.org/files/default.rb", true).and_return(StringIO.new(@response)) @knife.should_receive(:pretty_print).with(@response) @knife.run end end describe "with 4 arguments: name, version, segment and filename -- with specificity" do before(:each) do @knife.name_args = [ "cookbook_name", "0.1.0", "files", "afile.rb" ] @cookbook_response = Chef::CookbookVersion.new("cookbook_name") @cookbook_response.manifest = { "files" => [ { :name => "afile.rb", :path => "files/host-examplehost.example.org/afile.rb", :checksum => "1111", :specificity => "host-examplehost.example.org", :url => "http://example.org/files/1111" }, { :name => "afile.rb", :path => "files/ubuntu-9.10/afile.rb", :checksum => "2222", :specificity => "ubuntu-9.10", :url => "http://example.org/files/2222" }, { :name => "afile.rb", :path => "files/ubuntu/afile.rb", :checksum => "3333", :specificity => "ubuntu", :url => "http://example.org/files/3333" }, { :name => "afile.rb", :path => "files/default/afile.rb", :checksum => "4444", :specificity => "default", :url => "http://example.org/files/4444" }, ] } @response = "Example recipe text" end describe "with --fqdn" do it "should pass the fqdn" do @knife.config[:platform] = "example_platform" @knife.config[:platform_version] = "1.0" @knife.config[:fqdn] = "examplehost.example.org" @rest.should_receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response) @rest.should_receive(:get_rest).with("http://example.org/files/1111", true).and_return(StringIO.new(@response)) @knife.should_receive(:pretty_print).with(@response) @knife.run end end describe "and --platform" do it "should pass the platform" do @knife.config[:platform] = "ubuntu" @knife.config[:platform_version] = "1.0" @knife.config[:fqdn] = "differenthost.example.org" @rest.should_receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response) @rest.should_receive(:get_rest).with("http://example.org/files/3333", true).and_return(StringIO.new(@response)) @knife.should_receive(:pretty_print).with(@response) @knife.run end end describe "and --platform-version" do it "should pass the platform" do @knife.config[:platform] = "ubuntu" @knife.config[:platform_version] = "9.10" @knife.config[:fqdn] = "differenthost.example.org" @rest.should_receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response) @rest.should_receive(:get_rest).with("http://example.org/files/2222", true).and_return(StringIO.new(@response)) @knife.should_receive(:pretty_print).with(@response) @knife.run end end describe "with none of the arguments, it should use the default" do it "should pass them all" do @rest.should_receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response) @rest.should_receive(:get_rest).with("http://example.org/files/4444", true).and_return(StringIO.new(@response)) @knife.should_receive(:pretty_print).with(@response) @knife.run end end end end end chef-11.8.2/spec/unit/knife/node_list_spec.rb0000644000004100000410000000403112254362222021062 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::NodeList do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" Chef::Config[:environment] = nil # reset this value each time, as it is not reloaded @knife = Chef::Knife::NodeList.new @knife.stub!(:output).and_return(true) @list = { "foo" => "http://example.com/foo", "bar" => "http://example.com/foo" } Chef::Node.stub!(:list).and_return(@list) Chef::Node.stub!(:list_by_environment).and_return(@list) end describe "run" do it "should list all of the nodes if -E is not specified" do Chef::Node.should_receive(:list).and_return(@list) @knife.run end it "should pretty print the list" do Chef::Node.should_receive(:list).and_return(@list) @knife.should_receive(:output).with([ "bar", "foo" ]) @knife.run end it "should list nodes in the specific environment if -E ENVIRONMENT is specified" do Chef::Config[:environment] = "prod" Chef::Node.should_receive(:list_by_environment).with("prod").and_return(@list) @knife.run end describe "with -w or --with-uri" do it "should pretty print the hash" do @knife.config[:with_uri] = true Chef::Node.should_receive(:list).and_return(@list) @knife.should_receive(:output).with(@list) @knife.run end end end end chef-11.8.2/spec/unit/knife/data_bag_show_spec.rb0000644000004100000410000000756312254362222021701 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Seth Falcon () # Copyright:: Copyright (c) 2008-2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/data_bag_item' require 'chef/encrypted_data_bag_item' require 'chef/json_compat' require 'tempfile' describe Chef::Knife::DataBagShow do before do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::DataBagShow.new @knife.config[:format] = 'json' @rest = mock("Chef::REST") @knife.stub!(:rest).and_return(@rest) @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) end it "prints the ids of the data bag items when given a bag name" do @knife.instance_variable_set(:@name_args, ['bag_o_data']) data_bag_contents = { "baz"=>"http://localhost:4000/data/bag_o_data/baz", "qux"=>"http://localhost:4000/data/bag_o_data/qux"} Chef::DataBag.should_receive(:load).and_return(data_bag_contents) expected = %q|[ "baz", "qux" ]| @knife.run @stdout.string.strip.should == expected end it "prints the contents of the data bag item when given a bag and item name" do @knife.instance_variable_set(:@name_args, ['bag_o_data', 'an_item']) data_item = Chef::DataBagItem.new.tap {|item| item.raw_data = {"id" => "an_item", "zsh" => "victory_through_tabbing"}} Chef::DataBagItem.should_receive(:load).with('bag_o_data', 'an_item').and_return(data_item) @knife.run Chef::JSONCompat.from_json(@stdout.string).should == data_item.raw_data end describe "encrypted data bag items" do before(:each) do @secret = "abc123SECRET" @plain_data = { "id" => "item_name", "greeting" => "hello", "nested" => { "a1" => [1, 2, 3], "a2" => { "b1" => true }} } @enc_data = Chef::EncryptedDataBagItem.encrypt_data_bag_item(@plain_data, @secret) @knife.instance_variable_set(:@name_args, ['bag_name', 'item_name']) @secret_file = Tempfile.new("encrypted_data_bag_secret_file_test") @secret_file.puts(@secret) @secret_file.flush end after do @secret_file.close @secret_file.unlink end it "prints the decrypted contents of an item when given --secret" do @knife.stub!(:config).and_return({:secret => @secret}) Chef::EncryptedDataBagItem.should_receive(:load). with('bag_name', 'item_name', @secret). and_return(Chef::EncryptedDataBagItem.new(@enc_data, @secret)) @knife.run Chef::JSONCompat.from_json(@stdout.string).should == @plain_data end it "prints the decrypted contents of an item when given --secret_file" do @knife.stub!(:config).and_return({:secret_file => @secret_file.path}) Chef::EncryptedDataBagItem.should_receive(:load). with('bag_name', 'item_name', @secret). and_return(Chef::EncryptedDataBagItem.new(@enc_data, @secret)) @knife.run Chef::JSONCompat.from_json(@stdout.string).should == @plain_data end end describe "command line parsing" do it "prints help if given no arguments" do @knife.instance_variable_set(:@name_args, []) lambda { @knife.run }.should raise_error(SystemExit) @stdout.string.should match(/^knife data bag show BAG \[ITEM\] \(options\)/) end end end chef-11.8.2/spec/unit/knife/role_from_file_spec.rb0000644000004100000410000000405412254362222022072 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' Chef::Knife::RoleFromFile.load_deps describe Chef::Knife::RoleFromFile do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::RoleFromFile.new @knife.config = { :print_after => nil } @knife.name_args = [ "adam.rb" ] @knife.stub!(:output).and_return(true) @knife.stub!(:confirm).and_return(true) @role = Chef::Role.new() @role.stub!(:save) @knife.loader.stub!(:load_from).and_return(@role) @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) end describe "run" do it "should load from a file" do @knife.loader.should_receive(:load_from).with('roles', 'adam.rb').and_return(@role) @knife.run end it "should not print the role" do @knife.should_not_receive(:output) @knife.run end describe "with -p or --print-after" do it "should print the role" do @knife.config[:print_after] = true @knife.should_receive(:output) @knife.run end end end describe "run with multiple arguments" do it "should load each file" do @knife.name_args = [ "adam.rb", "caleb.rb" ] @knife.loader.should_receive(:load_from).with('roles', 'adam.rb').and_return(@role) @knife.loader.should_receive(:load_from).with('roles', 'caleb.rb').and_return(@role) @knife.run end end end chef-11.8.2/spec/unit/knife/cookbook_upload_spec.rb0000644000004100000410000001557112254362222022267 0ustar www-datawww-data# # Author:: Matthew Kent () # Author:: Steven Danna () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper")) require 'chef/cookbook_uploader' require 'timeout' describe Chef::Knife::CookbookUpload do before(:each) do @knife = Chef::Knife::CookbookUpload.new @knife.name_args = ['test_cookbook'] @cookbook = Chef::CookbookVersion.new('test_cookbook') @cookbook_loader = {} @cookbook_loader.stub!(:[]).and_return(@cookbook) @cookbook_loader.stub!(:merged_cookbooks).and_return([]) @cookbook_loader.stub!(:load_cookbooks).and_return(@cookbook_loader) Chef::CookbookLoader.stub!(:new).and_return(@cookbook_loader) @output = StringIO.new @knife.ui.stub!(:stdout).and_return(@output) @knife.ui.stub!(:stderr).and_return(@output) end describe 'run' do before(:each) do @cookbook_uploader = stub(:upload_cookbooks => nil) Chef::CookbookUploader.stub(:new => @cookbook_uploader) Chef::CookbookVersion.stub(:list_all_versions).and_return({}) end it 'should print usage and exit when a cookbook name is not provided' do @knife.name_args = [] @knife.should_receive(:show_usage) @knife.ui.should_receive(:fatal) lambda { @knife.run }.should raise_error(SystemExit) end describe 'when specifying a cookbook name' do it 'should upload the cookbook' do @knife.should_receive(:upload).once @knife.run end it 'should report on success' do @knife.should_receive(:upload).once @knife.ui.should_receive(:info).with(/Uploaded 1 cookbook/) @knife.run end end describe 'when specifying the same cookbook name twice' do it 'should upload the cookbook only once' do @knife.name_args = ['test_cookbook', 'test_cookbook'] @knife.should_receive(:upload).once @knife.run end end describe 'when specifying a cookbook name among many' do before(:each) do @knife.name_args = ['test_cookbook1'] @cookbooks = { 'test_cookbook1' => Chef::CookbookVersion.new('test_cookbook1'), 'test_cookbook2' => Chef::CookbookVersion.new('test_cookbook2'), 'test_cookbook3' => Chef::CookbookVersion.new('test_cookbook3') } @cookbook_loader = {} @cookbook_loader.stub!(:merged_cookbooks).and_return([]) @cookbook_loader.stub(:[]) { |ckbk| @cookbooks[ckbk] } Chef::CookbookLoader.stub!(:new).and_return(@cookbook_loader) end it "should read only one cookbook" do @cookbook_loader.should_receive(:[]).once.with('test_cookbook1') @knife.run end it "should not read all cookbooks" do @cookbook_loader.should_not_receive(:load_cookbooks) @knife.run end it "should upload only one cookbook" do @knife.should_receive(:upload).exactly(1).times @knife.run end end # This is testing too much. We should break it up. describe 'when specifying a cookbook name with dependencies' do it "should upload all dependencies once" do @knife.name_args = ["test_cookbook2"] @knife.config[:depends] = true @test_cookbook1 = Chef::CookbookVersion.new('test_cookbook1') @test_cookbook2 = Chef::CookbookVersion.new('test_cookbook2') @test_cookbook3 = Chef::CookbookVersion.new('test_cookbook3') @test_cookbook2.metadata.depends("test_cookbook3") @test_cookbook3.metadata.depends("test_cookbook1") @test_cookbook3.metadata.depends("test_cookbook2") @cookbook_loader.stub!(:[]) do |ckbk| { "test_cookbook1" => @test_cookbook1, "test_cookbook2" => @test_cookbook2, "test_cookbook3" => @test_cookbook3 }[ckbk] end @knife.stub!(:cookbook_names).and_return(["test_cookbook1", "test_cookbook2", "test_cookbook3"]) @knife.should_receive(:upload).exactly(3).times Timeout::timeout(5) do @knife.run end.should_not raise_error(Timeout::Error) end end it "should freeze the version of the cookbooks if --freeze is specified" do @knife.config[:freeze] = true @cookbook.should_receive(:freeze_version).once @knife.run end describe 'with -a or --all' do before(:each) do @knife.config[:all] = true @test_cookbook1 = Chef::CookbookVersion.new('test_cookbook1') @test_cookbook2 = Chef::CookbookVersion.new('test_cookbook2') @cookbook_loader.stub!(:each).and_yield("test_cookbook1", @test_cookbook1).and_yield("test_cookbook2", @test_cookbook2) @cookbook_loader.stub!(:cookbook_names).and_return(["test_cookbook1", "test_cookbook2"]) end it 'should upload all cookbooks' do @knife.should_receive(:upload).once @knife.run end it 'should report on success' do @knife.should_receive(:upload).once @knife.ui.should_receive(:info).with(/Uploaded all cookbooks/) @knife.run end it 'should update the version constraints for an environment' do @knife.stub!(:assert_environment_valid!).and_return(true) @knife.config[:environment] = "production" @knife.should_receive(:update_version_constraints).once @knife.run end end describe 'when a frozen cookbook exists on the server' do it 'should fail to replace it' do exception = Chef::Exceptions::CookbookFrozen.new @cookbook_uploader.should_receive(:upload_cookbooks). and_raise(exception) @knife.ui.stub(:error) @knife.ui.should_receive(:error).with(exception) lambda { @knife.run }.should raise_error(SystemExit) end it 'should not update the version constraints for an environment' do @knife.stub!(:assert_environment_valid!).and_return(true) @knife.config[:environment] = "production" @knife.stub!(:upload).and_raise(Chef::Exceptions::CookbookFrozen) @knife.ui.should_receive(:error).with(/Failed to upload 1 cookbook/) @knife.ui.should_receive(:warn).with(/Not updating version constraints/) @knife.should_not_receive(:update_version_constraints) lambda { @knife.run }.should raise_error(SystemExit) end end end # run end chef-11.8.2/spec/unit/knife/client_list_spec.rb0000644000004100000410000000202012254362222021407 0ustar www-datawww-data# # Author:: Thomas Bishop () # Copyright:: Copyright (c) 2011 Thomas Bishop # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::ClientList do before(:each) do @knife = Chef::Knife::ClientList.new @knife.name_args = [ 'adam' ] end describe 'run' do it 'should list the clients' do Chef::ApiClient.should_receive(:list) @knife.should_receive(:format_list_for_display) @knife.run end end end chef-11.8.2/spec/unit/knife/cookbook_metadata_spec.rb0000644000004100000410000001713512254362222022561 0ustar www-datawww-data# # Author:: Thomas Bishop () # Copyright:: Copyright (c) 2011 Thomas Bishop # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::CookbookMetadata do before(:each) do @knife = Chef::Knife::CookbookMetadata.new @knife.name_args = ['foobar'] @cookbook_dir = Dir.mktmpdir @json_data = '{ "version": "1.0.0" }' @stdout = StringIO.new @stderr = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) @knife.ui.stub!(:stderr).and_return(@stderr) end describe 'run' do it 'should print an error and exit if a cookbook name was not provided' do @knife.name_args = [] @knife.ui.should_receive(:error).with(/you must specify the cookbook.+use the --all/i) lambda { @knife.run }.should raise_error(SystemExit) end it 'should print an error and exit if an empty cookbook name was provided' do @knife.name_args = [''] @knife.ui.should_receive(:error).with(/you must specify the cookbook.+use the --all/i) lambda { @knife.run }.should raise_error(SystemExit) end it 'should generate the metadata for the cookbook' do @knife.should_receive(:generate_metadata).with('foobar') @knife.run end describe 'with -a or --all' do before(:each) do @knife.config[:all] = true @foo = Chef::CookbookVersion.new('foo') @foo.version = '1.0.0' @bar = Chef::CookbookVersion.new('bar') @bar.version = '2.0.0' @cookbook_loader = { "foo" => @foo, "bar" => @bar } @cookbook_loader.should_receive(:load_cookbooks).and_return(@cookbook_loader) @knife.should_receive(:generate_metadata).with('foo') @knife.should_receive(:generate_metadata).with('bar') end it 'should generate the metadata for each cookbook' do Chef::Config[:cookbook_path] = @cookbook_dir Chef::CookbookLoader.should_receive(:new).with(@cookbook_dir).and_return(@cookbook_loader) @knife.run end describe 'and with -o or --cookbook-path' do it 'should look in the provided path and generate cookbook metadata' do @knife.config[:cookbook_path] = '/opt/chef/cookbooks' Chef::CookbookLoader.should_receive(:new).with('/opt/chef/cookbooks').and_return(@cookbook_loader) @knife.run end end end end describe 'generate_metadata' do before(:each) do @knife.config[:cookbook_path] = @cookbook_dir File.stub!(:expand_path).with("#{@cookbook_dir}/foobar/metadata.rb"). and_return("#{@cookbook_dir}/foobar/metadata.rb") end it 'should generate the metadata from metadata.rb if it exists' do File.should_receive(:exists?).with("#{@cookbook_dir}/foobar/metadata.rb"). and_return(true) @knife.should_receive(:generate_metadata_from_file).with('foobar', "#{@cookbook_dir}/foobar/metadata.rb") @knife.run end it 'should validate the metadata json if metadata.rb does not exist' do File.should_receive(:exists?).with("#{@cookbook_dir}/foobar/metadata.rb"). and_return(false) @knife.should_receive(:validate_metadata_json).with(@cookbook_dir, 'foobar') @knife.run end end describe 'generate_metadata_from_file' do before(:each) do @metadata_mock = mock('metadata') @json_file_mock = mock('json_file') end it 'should generate the metatdata json from metatdata.rb' do Chef::Cookbook::Metadata.stub!(:new).and_return(@metadata_mock) @metadata_mock.should_receive(:name).with('foobar') @metadata_mock.should_receive(:from_file).with("#{@cookbook_dir}/foobar/metadata.rb") File.should_receive(:open).with("#{@cookbook_dir}/foobar/metadata.json", 'w'). and_yield(@json_file_mock) @json_file_mock.should_receive(:write).with(@json_data) Chef::JSONCompat.should_receive(:to_json_pretty).with(@metadata_mock). and_return(@json_data) @knife.generate_metadata_from_file('foobar', "#{@cookbook_dir}/foobar/metadata.rb") @stdout.string.should match /generating metadata for foobar from #{@cookbook_dir}\/foobar\/metadata\.rb/im end { Chef::Exceptions::ObsoleteDependencySyntax => 'obsolote dependency', Chef::Exceptions::InvalidVersionConstraint => 'invalid version constraint' }.each_pair do |klass, description| it "should print an error and exit when an #{description} syntax exception is encountered" do exception = klass.new("#{description} blah") Chef::Cookbook::Metadata.stub!(:new).and_raise(exception) lambda { @knife.generate_metadata_from_file('foobar', "#{@cookbook_dir}/foobar/metadata.rb") }.should raise_error(SystemExit) @stderr.string.should match /error: the cookbook 'foobar' contains invalid or obsolete metadata syntax/im @stderr.string.should match /in #{@cookbook_dir}\/foobar\/metadata\.rb/im @stderr.string.should match /#{description} blah/im end end end describe 'validate_metadata_json' do it 'should validate the metadata json' do File.should_receive(:exist?).with("#{@cookbook_dir}/foobar/metadata.json"). and_return(true) IO.should_receive(:read).with("#{@cookbook_dir}/foobar/metadata.json"). and_return(@json_data) Chef::Cookbook::Metadata.should_receive(:validate_json).with(@json_data) @knife.validate_metadata_json(@cookbook_dir, 'foobar') end it 'should not try to validate the metadata json if the file does not exist' do File.should_receive(:exist?).with("#{@cookbook_dir}/foobar/metadata.json"). and_return(false) IO.should_not_receive(:read) Chef::Cookbook::Metadata.should_not_receive(:validate_json) @knife.validate_metadata_json(@cookbook_dir, 'foobar') end { Chef::Exceptions::ObsoleteDependencySyntax => 'obsolote dependency', Chef::Exceptions::InvalidVersionConstraint => 'invalid version constraint' }.each_pair do |klass, description| it "should print an error and exit when an #{description} syntax exception is encountered" do File.should_receive(:exist?).with("#{@cookbook_dir}/foobar/metadata.json"). and_return(true) IO.should_receive(:read).with("#{@cookbook_dir}/foobar/metadata.json"). and_return(@json_data) exception = klass.new("#{description} blah") Chef::Cookbook::Metadata.stub!(:validate_json).and_raise(exception) lambda { @knife.validate_metadata_json(@cookbook_dir, 'foobar') }.should raise_error(SystemExit) @stderr.string.should match /error: the cookbook 'foobar' contains invalid or obsolete metadata syntax/im @stderr.string.should match /in #{@cookbook_dir}\/foobar\/metadata\.json/im @stderr.string.should match /#{description} blah/im end end end end chef-11.8.2/spec/unit/knife/core/0000755000004100000410000000000012254362222016475 5ustar www-datawww-datachef-11.8.2/spec/unit/knife/core/object_loader_spec.rb0000644000004100000410000000450412254362222022633 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Author:: Juanje Ojeda () # Copyright:: Copyright (c) 2011-2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/knife/core/object_loader' describe Chef::Knife::Core::ObjectLoader do before(:each) do @knife = Chef::Knife.new @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) Dir.chdir(File.join(CHEF_SPEC_DATA, 'object_loader')) end shared_examples_for "Chef object" do |chef_class| it "should create a #{chef_class} object" do @object.should be_a_kind_of(chef_class) end it "should has a attribute 'name'" do @object.name.should eql('test') end end { 'nodes' => Chef::Node, 'roles' => Chef::Role, 'environments' => Chef::Environment }.each do |repo_location, chef_class| describe "when the file is a #{chef_class}" do before do @loader = Chef::Knife::Core::ObjectLoader.new(chef_class, @knife.ui) end describe "when the file is a Ruby" do before do @object = @loader.load_from(repo_location, 'test.rb') end it_behaves_like "Chef object", chef_class end #NOTE: This is check for the bug described at CHEF-2352 describe "when the file is a JSON" do describe "and it has defined 'json_class'" do before do @object = @loader.load_from(repo_location, 'test_json_class.json') end it_behaves_like "Chef object", chef_class end describe "and it has not defined 'json_class'" do before do @object = @loader.load_from(repo_location, 'test.json') end it_behaves_like "Chef object", chef_class end end end end end chef-11.8.2/spec/unit/knife/core/cookbook_scm_repo_spec.rb0000644000004100000410000001676212254362222023545 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/knife/core/cookbook_scm_repo' describe Chef::Knife::CookbookSCMRepo do before do @repo_path = File.join(CHEF_SPEC_DATA, 'cookbooks') @stdout, @stderr, @stdin = StringIO.new, StringIO.new, StringIO.new @ui = Chef::Knife::UI.new(@stdout, @stderr, @stdin, {}) @cookbook_repo = Chef::Knife::CookbookSCMRepo.new(@repo_path, @ui, :default_branch => 'master') @branch_list = Mixlib::ShellOut.new @branch_list.stdout.replace(<<-BRANCHES) chef-vendor-apache2 chef-vendor-build-essential chef-vendor-dynomite chef-vendor-ganglia chef-vendor-graphite chef-vendor-python chef-vendor-absent-new BRANCHES end it "has a path to the cookbook repo" do @cookbook_repo.repo_path.should == @repo_path end it "has a default branch" do @cookbook_repo.default_branch.should == 'master' end describe "when sanity checking the repo" do it "exits when the directory does not exist" do ::File.should_receive(:directory?).with(@repo_path).and_return(false) lambda {@cookbook_repo.sanity_check}.should raise_error(SystemExit) end describe "and the repo dir exists" do before do ::File.stub!(:directory?).with(@repo_path).and_return(true) end it "exits when there is no git repo" do ::File.stub!(:directory?).with(/.*\.git/).and_return(false) lambda {@cookbook_repo.sanity_check}.should raise_error(SystemExit) end describe "and the repo is a git repo" do before do ::File.stub!(:directory?).with(File.join(@repo_path, '.git')).and_return(true) end it "exits when the default branch doesn't exist" do @nobranches = Mixlib::ShellOut.new.tap {|s|s.stdout.replace "\n"} @cookbook_repo.should_receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@nobranches) lambda {@cookbook_repo.sanity_check}.should raise_error(SystemExit) end describe "and the default branch exists" do before do @master_branch = Mixlib::ShellOut.new @master_branch.stdout.replace "* master\n" @cookbook_repo.should_receive(:shell_out!).with("git branch --no-color", :cwd => @repo_path).and_return(@master_branch) end it "exits when the git repo is dirty" do @dirty_status = Mixlib::ShellOut.new @dirty_status.stdout.replace(<<-DIRTY) M chef/lib/chef/knife/cookbook_site_vendor.rb DIRTY @cookbook_repo.should_receive(:shell_out!).with('git status --porcelain', :cwd => @repo_path).and_return(@dirty_status) lambda {@cookbook_repo.sanity_check}.should raise_error(SystemExit) end describe "and the repo is clean" do before do @clean_status = Mixlib::ShellOut.new.tap {|s| s.stdout.replace("\n")} @cookbook_repo.stub!(:shell_out!).with('git status --porcelain', :cwd => @repo_path).and_return(@clean_status) end it "passes the sanity check" do @cookbook_repo.sanity_check end end end end end end it "resets to default state by checking out the default branch" do @cookbook_repo.should_receive(:shell_out!).with('git checkout master', :cwd => @repo_path) @cookbook_repo.reset_to_default_state end it "determines if a the pristine copy branch exists" do @cookbook_repo.should_receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list) @cookbook_repo.branch_exists?("chef-vendor-apache2").should be_true @cookbook_repo.should_receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list) @cookbook_repo.branch_exists?("chef-vendor-nginx").should be_false end it "determines if a the branch not exists correctly without substring search" do @cookbook_repo.should_receive(:shell_out!).twice.with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list) @cookbook_repo.should_not be_branch_exists("chef-vendor-absent") @cookbook_repo.should be_branch_exists("chef-vendor-absent-new") end describe "when the pristine copy branch does not exist" do it "prepares for import by creating the pristine copy branch" do @cookbook_repo.should_receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list) @cookbook_repo.should_receive(:shell_out!).with('git checkout -b chef-vendor-nginx', :cwd => @repo_path) @cookbook_repo.prepare_to_import("nginx") end end describe "when the pristine copy branch does exist" do it "prepares for import by checking out the pristine copy branch" do @cookbook_repo.should_receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list) @cookbook_repo.should_receive(:shell_out!).with('git checkout chef-vendor-apache2', :cwd => @repo_path) @cookbook_repo.prepare_to_import("apache2") end end describe "when the pristine copy branch was not updated by the changes" do before do @updates = Mixlib::ShellOut.new @updates.stdout.replace("\n") @cookbook_repo.stub!(:shell_out!).with('git status --porcelain -- apache2', :cwd => @repo_path).and_return(@updates) end it "shows no changes in the pristine copy" do @cookbook_repo.updated?('apache2').should be_false end it "does nothing to finalize the updates" do @cookbook_repo.finalize_updates_to('apache2', '1.2.3').should be_false end end describe "when the pristine copy branch was updated by the changes" do before do @updates = Mixlib::ShellOut.new @updates.stdout.replace(" M cookbooks/apache2/recipes/default.rb\n") @cookbook_repo.stub!(:shell_out!).with('git status --porcelain -- apache2', :cwd => @repo_path).and_return(@updates) end it "shows changes in the pristine copy" do @cookbook_repo.updated?('apache2').should be_true end it "commits the changes to the repo and tags the commit" do @cookbook_repo.should_receive(:shell_out!).with("git add apache2", :cwd => @repo_path) @cookbook_repo.should_receive(:shell_out!).with("git commit -m \"Import apache2 version 1.2.3\" -- apache2", :cwd => @repo_path) @cookbook_repo.should_receive(:shell_out!).with("git tag -f cookbook-site-imported-apache2-1.2.3", :cwd => @repo_path) @cookbook_repo.finalize_updates_to("apache2", "1.2.3").should be_true end end describe "when a custom default branch is specified" do before do @cookbook_repo = Chef::Knife::CookbookSCMRepo.new(@repo_path, @ui, :default_branch => 'develop') end it "resets to default state by checking out the default branch" do @cookbook_repo.should_receive(:shell_out!).with('git checkout develop', :cwd => @repo_path) @cookbook_repo.reset_to_default_state end end end chef-11.8.2/spec/unit/knife/core/subcommand_loader_spec.rb0000644000004100000410000000643412254362222023521 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::SubcommandLoader do before do @home = File.join(CHEF_SPEC_DATA, 'knife-home') @env = {'HOME' => @home} @loader = Chef::Knife::SubcommandLoader.new(File.join(CHEF_SPEC_DATA, 'knife-site-subcommands'), @env) end it "builds a list of the core subcommand file require paths" do @loader.subcommand_files.should_not be_empty @loader.subcommand_files.each do |require_path| require_path.should match(/chef\/knife\/.*|plugins\/knife\/.*/) end end it "finds files installed via rubygems" do @loader.find_subcommands_via_rubygems.should include('chef/knife/node_create') @loader.find_subcommands_via_rubygems.each {|rel_path, abs_path| abs_path.should match(%r[chef/knife/.+])} end it "finds files from latest version of installed gems" do gems = [ double('knife-ec2-0.5.12') ] gem_files = [ '/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/ec2_base.rb', '/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/ec2_otherstuff.rb' ] $LOAD_PATH.should_receive(:map).and_return([]) if Gem::Specification.respond_to? :latest_specs Gem::Specification.should_receive(:latest_specs).and_return(gems) gems[0].should_receive(:matches_for_glob).with(/chef\/knife\/\*\.rb{(.*),\.rb,(.*)}/).and_return(gem_files) else Gem.source_index.should_receive(:latest_specs).and_return(gems) gems[0].should_receive(:require_paths).twice.and_return(['lib']) gems[0].should_receive(:full_gem_path).and_return('/usr/lib/ruby/gems/knife-ec2-0.5.12') Dir.should_receive(:[]).with('/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/*.rb').and_return(gem_files) end @loader.should_receive(:find_subcommands_via_dirglob).and_return({}) @loader.find_subcommands_via_rubygems.values.select { |file| file =~ /knife-ec2/ }.sort.should == gem_files end it "finds files using a dirglob when rubygems is not available" do @loader.find_subcommands_via_dirglob.should include('chef/knife/node_create') @loader.find_subcommands_via_dirglob.each {|rel_path, abs_path| abs_path.should match(%r[chef/knife/.+])} end it "finds user-specific subcommands in the user's ~/.chef directory" do expected_command = File.join(@home, '.chef', 'plugins', 'knife', 'example_home_subcommand.rb') @loader.site_subcommands.should include(expected_command) end it "finds repo specific subcommands by searching for a .chef directory" do expected_command = File.join(CHEF_SPEC_DATA, 'knife-site-subcommands', 'plugins', 'knife', 'example_subcommand.rb') @loader.site_subcommands.should include(expected_command) end end chef-11.8.2/spec/unit/knife/core/ui_spec.rb0000644000004100000410000003353512254362222020462 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tim Hinderliter () # Author:: Daniel DeLeo () # Author:: John Keiser () # Copyright:: Copyright (c) 2008, 2011, 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::UI do before do @out, @err, @in = StringIO.new, StringIO.new, StringIO.new @config = {} @ui = Chef::Knife::UI.new(@out, @err, @in, @config) end describe "edit" do ruby_for_json = { 'foo' => 'bar' } json_from_ruby = "{\n \"foo\": \"bar\"\n}" json_from_editor = "{\n \"bar\": \"foo\"\n}" ruby_from_editor = { 'bar' => 'foo' } my_editor = "veeeye" temp_path = "/tmp/bar/baz" let(:subject) { @ui.edit_data(ruby_for_json, parse_output) } let(:parse_output) { false } context "when editing is disabled" do before do @ui.config[:disable_editing] = true stub_const("Tempfile", double) # Tempfiles should never be invoked end context "when parse_output is false" do it "returns pretty json string" do expect(subject).to eql(json_from_ruby) end end context "when parse_output is true" do let(:parse_output) { true } it "returns a ruby object" do expect(subject).to eql(ruby_for_json) end end end context "when editing is enabled" do before do @ui.config[:disable_editing] = false @ui.config[:editor] = my_editor @mock = mock('Tempfile') @mock.should_receive(:sync=).with(true) @mock.should_receive(:puts).with(json_from_ruby) @mock.should_receive(:close) @mock.should_receive(:path).at_least(:once).and_return(temp_path) Tempfile.should_receive(:open).with([ 'knife-edit-', '.json' ]).and_yield(@mock) end context "and the editor works" do before do @ui.should_receive(:system).with("#{my_editor} #{temp_path}").and_return(true) IO.should_receive(:read).with(temp_path).and_return(json_from_editor) end context "when parse_output is false" do it "returns an edited pretty json string" do expect(subject).to eql(json_from_editor) end end context "when parse_output is true" do let(:parse_output) { true } it "returns an edited ruby object" do expect(subject).to eql(ruby_from_editor) end end end context "when running the editor fails with nil" do before do @ui.should_receive(:system).with("#{my_editor} #{temp_path}").and_return(nil) IO.should_not_receive(:read) end it "throws an exception" do expect{ subject }.to raise_error(RuntimeError) end end context "when running the editor fails with false" do before do @ui.should_receive(:system).with("#{my_editor} #{temp_path}").and_return(false) IO.should_not_receive(:read) end it "throws an exception" do expect{ subject }.to raise_error(RuntimeError) end end end context "when editing and not stubbing Tempfile (semi-functional test)" do before do @ui.config[:disable_editing] = false @ui.config[:editor] = my_editor @tempfile = Tempfile.new([ 'knife-edit-', '.json' ]) Tempfile.should_receive(:open).with([ 'knife-edit-', '.json' ]).and_yield(@tempfile) end context "and the editor works" do before do @ui.should_receive(:system).with("#{my_editor} #{@tempfile.path}").and_return(true) IO.should_receive(:read).with(@tempfile.path).and_return(json_from_editor) end context "when parse_output is false" do it "returns an edited pretty json string" do expect(subject).to eql(json_from_editor) end it "the tempfile should have mode 0600", :unix_only do # XXX: this looks odd because we're really testing Tempfile.new here expect(File.stat(@tempfile.path).mode & 0777).to eql(0600) expect(subject).to eql(json_from_editor) end end context "when parse_output is true" do let(:parse_output) { true } it "returns an edited ruby object" do expect(subject).to eql(ruby_from_editor) end it "the tempfile should have mode 0600", :unix_only do # XXX: this looks odd because we're really testing Tempfile.new here expect(File.stat(@tempfile.path).mode & 0777).to eql(0600) expect(subject).to eql(ruby_from_editor) end end end end end describe "format_list_for_display" do it "should print the full hash if --with-uri is true" do @ui.config[:with_uri] = true @ui.format_list_for_display({ :marcy => :playground }).should == { :marcy => :playground } end it "should print only the keys if --with-uri is false" do @ui.config[:with_uri] = false @ui.format_list_for_display({ :marcy => :playground }).should == [ :marcy ] end end shared_examples "an output mehthod handling IO exceptions" do |method| it "should throw Errno::EIO exceptions" do @out.stub(:puts).and_raise(Errno::EIO) @err.stub(:puts).and_raise(Errno::EIO) lambda {@ui.send(method, "hi")}.should raise_error(Errno::EIO) end it "should ignore Errno::EPIPE exceptions (CHEF-3516)" do @out.stub(:puts).and_raise(Errno::EPIPE) @err.stub(:puts).and_raise(Errno::EPIPE) lambda {@ui.send(method, "hi")}.should_not raise_error(Errno::EPIPE) end it "should throw Errno::EPIPE exceptions with -VV (CHEF-3516)" do @config[:verbosity] = 2 @out.stub(:puts).and_raise(Errno::EPIPE) @err.stub(:puts).and_raise(Errno::EPIPE) lambda {@ui.send(method, "hi")}.should raise_error(Errno::EPIPE) end end describe "output" do it_behaves_like "an output mehthod handling IO exceptions", :output it "formats strings appropriately" do @ui.output("hi") @out.string.should == "hi\n" end it "formats hashes appropriately" do @ui.output({'hi' => 'a', 'lo' => 'b' }) @out.string.should == < 'b', 'c' => 'd' }, { 'x' => 'y' }, { 'm' => 'n', 'o' => 'p' }]) @out.string.should == < [], 'b' => 'c' }) @out.string.should == < [ 'foo' ], 'b' => 'c' }) @out.string.should == < [ 'foo', 'bar' ], 'b' => 'c' }) @out.string.should == < [ [ 'foo' ] ], 'b' => 'c' }) @out.string.should == < [ [ 'foo', 'bar' ], [ 'baz', 'bjork' ] ], 'b' => 'c' }) @out.string.should == < { 'aa' => 'bb', 'cc' => 'dd' }, 'b' => 'c' }) @out.string.should == < { }, 'b' => 'c' }) @out.string.should == < :go } @ui.format_for_display(input).should == input end describe "with --attribute passed" do it "should return the deeply nested attribute" do input = { "gi" => { "go" => "ge" }, "id" => "sample-data-bag-item" } @ui.config[:attribute] = "gi.go" @ui.format_for_display(input).should == { "sample-data-bag-item" => { "gi.go" => "ge" } } end it "should return multiple attributes" do input = { "gi" => "go", "hi" => "ho", "id" => "sample-data-bag-item" } @ui.config[:attribute] = ["gi", "hi"] @ui.format_for_display(input).should == { "sample-data-bag-item" => { "gi" => "go", "hi"=> "ho" } } end end describe "with --run-list passed" do it "should return the run list" do input = Chef::Node.new input.name("sample-node") input.run_list("role[monkey]", "role[churchmouse]") @ui.config[:run_list] = true response = @ui.format_for_display(input) response["sample-node"]["run_list"][0].should == "role[monkey]" response["sample-node"]["run_list"][1].should == "role[churchmouse]" end end end describe "format_cookbook_list_for_display" do before(:each) do @item = { "cookbook_name" => { "url" => "http://url/cookbooks/cookbook", "versions" => [ { "version" => "3.0.0", "url" => "http://url/cookbooks/3.0.0" }, { "version" => "2.0.0", "url" => "http://url/cookbooks/2.0.0" }, { "version" => "1.0.0", "url" => "http://url/cookbooks/1.0.0" } ] } } end it "should return an array of the cookbooks with versions" do expected_response = [ "cookbook_name 3.0.0 2.0.0 1.0.0" ] response = @ui.format_cookbook_list_for_display(@item) response.should == expected_response end describe "with --with-uri" do it "should return the URIs" do response = { "cookbook_name"=>{ "1.0.0" => "http://url/cookbooks/1.0.0", "2.0.0" => "http://url/cookbooks/2.0.0", "3.0.0" => "http://url/cookbooks/3.0.0"} } @ui.config[:with_uri] = true @ui.format_cookbook_list_for_display(@item).should == response end end end describe "confirm" do before(:each) do @question = "monkeys rule" @stdout = StringIO.new @ui.stub(:stdout).and_return(@stdout) @ui.stdin.stub!(:readline).and_return("y") end it "should return true if you answer Y" do @ui.stdin.stub!(:readline).and_return("Y") @ui.confirm(@question).should == true end it "should return true if you answer y" do @ui.stdin.stub!(:readline).and_return("y") @ui.confirm(@question).should == true end it "should exit 3 if you answer N" do @ui.stdin.stub!(:readline).and_return("N") lambda { @ui.confirm(@question) }.should raise_error(SystemExit) { |e| e.status.should == 3 } end it "should exit 3 if you answer n" do @ui.stdin.stub!(:readline).and_return("n") lambda { @ui.confirm(@question) }.should raise_error(SystemExit) { |e| e.status.should == 3 } end describe "with --y or --yes passed" do it "should return true" do @ui.config[:yes] = true @ui.confirm(@question).should == true end end describe "when asking for free-form user input" do it "asks a question and returns the answer provided by the user" do out = StringIO.new @ui.stub!(:stdout).and_return(out) @ui.stub!(:stdin).and_return(StringIO.new("http://mychefserver.example.com\n")) @ui.ask_question("your chef server URL?").should == "http://mychefserver.example.com" out.string.should == "your chef server URL?" end it "suggests a default setting and returns the default when the user's response only contains whitespace" do out = StringIO.new @ui.stub!(:stdout).and_return(out) @ui.stub!(:stdin).and_return(StringIO.new(" \n")) @ui.ask_question("your chef server URL? ", :default => 'http://localhost:4000').should == "http://localhost:4000" out.string.should == "your chef server URL? [http://localhost:4000] " end end end end chef-11.8.2/spec/unit/knife/core/bootstrap_context_spec.rb0000644000004100000410000001275212254362222023624 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/knife/core/bootstrap_context' describe Chef::Knife::Core::BootstrapContext do let(:config) { {:foo => :bar} } let(:run_list) { Chef::RunList.new('recipe[tmux]', 'role[base]') } let(:chef_config) do { :validation_key => File.join(CHEF_SPEC_DATA, 'ssl', 'private_key.pem'), :chef_server_url => 'http://chef.example.com:4444', :validation_client_name => 'chef-validator-testing' } end let(:secret_file) { File.join(CHEF_SPEC_DATA, 'bootstrap', 'encrypted_data_bag_secret') } subject(:bootstrap_context) { described_class.new(config, run_list, chef_config) } it "installs the same version of chef on the remote host" do bootstrap_context.bootstrap_version_string.should eq "--version #{Chef::VERSION}" end it "runs chef with the first-boot.json in the _default environment" do bootstrap_context.start_chef.should eq "chef-client -j /etc/chef/first-boot.json -E _default" end it "reads the validation key" do bootstrap_context.validation_key.should eq IO.read(File.join(CHEF_SPEC_DATA, 'ssl', 'private_key.pem')) end it "generates the config file data" do expected=<<-EXPECTED log_level :auto log_location STDOUT chef_server_url "http://chef.example.com:4444" validation_client_name "chef-validator-testing" # Using default node name (fqdn) EXPECTED bootstrap_context.config_content.should eq expected end describe "alternate chef-client path" do let(:chef_config){ {:chef_client_path => '/usr/local/bin/chef-client'} } it "runs chef-client from another path when specified" do bootstrap_context.start_chef.should eq "/usr/local/bin/chef-client -j /etc/chef/first-boot.json -E _default" end end describe "validation key path that contains a ~" do let(:chef_config){ {:validation_key => '~/my.key'} } it "reads the validation key when it contains a ~" do IO.should_receive(:read).with(File.expand_path("my.key", ENV['HOME'])) bootstrap_context.validation_key end end describe "when an explicit node name is given" do let(:config){ {:chef_node_name => 'foobar.example.com' }} it "sets the node name in the client.rb" do bootstrap_context.config_content.should match(/node_name "foobar\.example\.com"/) end end describe "when bootstrapping into a specific environment" do let(:chef_config){ {:environment => "prodtastic"} } it "starts chef in the configured environment" do bootstrap_context.start_chef.should == 'chef-client -j /etc/chef/first-boot.json -E prodtastic' end end describe "when installing a prerelease version of chef" do let(:config){ {:prerelease => true }} it "supplies --prerelease as the version string" do bootstrap_context.bootstrap_version_string.should eq '--prerelease' end end describe "when installing an explicit version of chef" do let(:chef_config) do { :knife => { :bootstrap_version => '123.45.678' } } end it "gives --version $VERSION as the version string" do bootstrap_context.bootstrap_version_string.should eq '--version 123.45.678' end end describe "when JSON attributes are given" do let(:config) { {:first_boot_attributes => {:baz => :quux}} } it "adds the attributes to first_boot" do bootstrap_context.first_boot.to_json.should eq({:baz => :quux, :run_list => run_list}.to_json) end end describe "when JSON attributes are NOT given" do it "sets first_boot equal to run_list" do bootstrap_context.first_boot.to_json.should eq({:run_list => run_list}.to_json) end end describe "when an encrypted_data_bag_secret is provided" do context "via config[:secret]" do let(:chef_config) do { :knife => {:secret => "supersekret" } } end it "reads the encrypted_data_bag_secret" do bootstrap_context.encrypted_data_bag_secret.should eq "supersekret" end end context "via config[:secret_file]" do let(:chef_config) do { :knife => {:secret_file => secret_file} } end it "reads the encrypted_data_bag_secret" do bootstrap_context.encrypted_data_bag_secret.should eq IO.read(secret_file) end end end describe "to support compatibility with existing templates" do it "sets the @config instance variable" do bootstrap_context.instance_variable_get(:@config).should eq config end it "sets the @run_list instance variable" do bootstrap_context.instance_variable_get(:@run_list).should eq run_list end describe "accepts encrypted_data_bag_secret via Chef::Config" do let(:chef_config) { {:encrypted_data_bag_secret => secret_file }} it "reads the encrypted_data_bag_secret" do bootstrap_context.encrypted_data_bag_secret.should eq IO.read(secret_file) end end end end chef-11.8.2/spec/unit/knife/ssh_spec.rb0000644000004100000410000002241012254362222017700 0ustar www-datawww-data# # Author:: Bryan McLellan # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'net/ssh' require 'net/ssh/multi' describe Chef::Knife::Ssh do before(:each) do Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem" end before do @knife = Chef::Knife::Ssh.new @knife.merge_configs @knife.config[:attribute] = "fqdn" @node_foo = Chef::Node.new @node_foo.automatic_attrs[:fqdn] = "foo.example.org" @node_foo.automatic_attrs[:ipaddress] = "10.0.0.1" @node_bar = Chef::Node.new @node_bar.automatic_attrs[:fqdn] = "bar.example.org" @node_bar.automatic_attrs[:ipaddress] = "10.0.0.2" end describe "#configure_session" do context "manual is set to false (default)" do before do @knife.config[:manual] = false @query = Chef::Search::Query.new end def configure_query(node_array) @query.stub!(:search).and_return([node_array]) Chef::Search::Query.stub!(:new).and_return(@query) end def self.should_return_specified_attributes it "returns an array of the attributes specified on the command line OR config file, if only one is set" do @knife.config[:attribute] = "ipaddress" @knife.config[:override_attribute] = "ipaddress" configure_query([@node_foo, @node_bar]) @knife.should_receive(:session_from_list).with(['10.0.0.1', '10.0.0.2']) @knife.configure_session end it "returns an array of the attributes specified on the command line even when a config value is set" do @knife.config[:attribute] = "config_file" # this value will be the config file @knife.config[:override_attribute] = "ipaddress" # this is the value of the command line via #configure_attribute configure_query([@node_foo, @node_bar]) @knife.should_receive(:session_from_list).with(['10.0.0.1', '10.0.0.2']) @knife.configure_session end end it "searchs for and returns an array of fqdns" do configure_query([@node_foo, @node_bar]) @knife.should_receive(:session_from_list).with(['foo.example.org', 'bar.example.org']) @knife.configure_session end should_return_specified_attributes context "when cloud hostnames are available" do before do @node_foo.automatic_attrs[:cloud][:public_hostname] = "ec2-10-0-0-1.compute-1.amazonaws.com" @node_bar.automatic_attrs[:cloud][:public_hostname] = "ec2-10-0-0-2.compute-1.amazonaws.com" end it "returns an array of cloud public hostnames" do configure_query([@node_foo, @node_bar]) @knife.should_receive(:session_from_list).with(['ec2-10-0-0-1.compute-1.amazonaws.com', 'ec2-10-0-0-2.compute-1.amazonaws.com']) @knife.configure_session end should_return_specified_attributes end it "should raise an error if no host are found" do configure_query([ ]) @knife.ui.should_receive(:fatal) @knife.should_receive(:exit).with(10) @knife.configure_session end context "when there are some hosts found but they do not have an attribute to connect with" do before do @query.stub!(:search).and_return([[@node_foo, @node_bar]]) @node_foo.automatic_attrs[:fqdn] = nil @node_bar.automatic_attrs[:fqdn] = nil Chef::Search::Query.stub!(:new).and_return(@query) end it "should raise a specific error (CHEF-3402)" do @knife.ui.should_receive(:fatal).with(/^2 nodes found/) @knife.should_receive(:exit).with(10) @knife.configure_session end end end context "manual is set to true" do before do @knife.config[:manual] = true end it "returns an array of provided values" do @knife.instance_variable_set(:@name_args, ["foo.example.org bar.example.org"]) @knife.should_receive(:session_from_list).with(['foo.example.org', 'bar.example.org']) @knife.configure_session end end end describe "#configure_attribute" do before do Chef::Config[:knife][:ssh_attribute] = nil @knife.config[:attribute] = nil end it "should return fqdn by default" do @knife.configure_attribute @knife.config[:attribute].should == "fqdn" end it "should return the value set in the configuration file" do Chef::Config[:knife][:ssh_attribute] = "config_file" @knife.configure_attribute @knife.config[:attribute].should == "config_file" end it "should return the value set on the command line" do @knife.config[:attribute] = "command_line" @knife.configure_attribute @knife.config[:attribute].should == "command_line" end it "should set override_attribute to the value of attribute from the command line" do @knife.config[:attribute] = "command_line" @knife.configure_attribute @knife.config[:attribute].should == "command_line" @knife.config[:override_attribute].should == "command_line" end it "should set override_attribute to the value of attribute from the config file" do Chef::Config[:knife][:ssh_attribute] = "config_file" @knife.configure_attribute @knife.config[:attribute].should == "config_file" @knife.config[:override_attribute].should == "config_file" end it "should prefer the command line over the config file for the value of override_attribute" do Chef::Config[:knife][:ssh_attribute] = "config_file" @knife.config[:attribute] = "command_line" @knife.configure_attribute @knife.config[:override_attribute].should == "command_line" end end describe "#session_from_list" do before :each do @knife.instance_variable_set(:@longest, 0) ssh_config = {:timeout => 50, :user => "locutus", :port => 23 } Net::SSH.stub!(:configuration_for).with('the.b.org').and_return(ssh_config) end it "uses the port from an ssh config file" do @knife.session_from_list(['the.b.org']) @knife.session.servers[0].port.should == 23 end it "uses the user from an ssh config file" do @knife.session_from_list(['the.b.org']) @knife.session.servers[0].user.should == "locutus" end end describe "#ssh_command" do let(:execution_channel) { double(:execution_channel, :on_data => nil) } let(:session_channel) { double(:session_channel, :request_pty => nil)} let(:execution_channel2) { double(:execution_channel, :on_data => nil) } let(:session_channel2) { double(:session_channel, :request_pty => nil)} let(:session) { double(:session, :loop => nil) } let(:command) { "false" } before do execution_channel. should_receive(:on_request). and_yield(nil, double(:data_stream, :read_long => exit_status)) session_channel. should_receive(:exec). with(command). and_yield(execution_channel, true) execution_channel2. should_receive(:on_request). and_yield(nil, double(:data_stream, :read_long => exit_status2)) session_channel2. should_receive(:exec). with(command). and_yield(execution_channel2, true) session. should_receive(:open_channel). and_yield(session_channel). and_yield(session_channel2) end context "both connections return 0" do let(:exit_status) { 0 } let(:exit_status2) { 0 } it "returns a 0 exit code" do @knife.ssh_command(command, session).should == 0 end end context "the first connection returns 1 and the second returns 0" do let(:exit_status) { 1 } let(:exit_status2) { 0 } it "returns a non-zero exit code" do @knife.ssh_command(command, session).should == 1 end end context "the first connection returns 1 and the second returns 2" do let(:exit_status) { 1 } let(:exit_status2) { 2 } it "returns a non-zero exit code" do @knife.ssh_command(command, session).should == 2 end end end describe "#run" do before do @query = Chef::Search::Query.new @query.should_receive(:search).and_return([[@node_foo]]) Chef::Search::Query.stub!(:new).and_return(@query) @knife.stub(:ssh_command).and_return(exit_code) @knife.name_args = ['*:*', 'false'] end context "with an error" do let(:exit_code) { 1 } it "should exit with a non-zero exit code" do @knife.should_receive(:exit).with(exit_code) @knife.run end end context "with no error" do let(:exit_code) { 0 } it "should not exit" do @knife.should_not_receive(:exit) @knife.run end end end end chef-11.8.2/spec/unit/knife/client_bulk_delete_spec.rb0000644000004100000410000000453712254362222022732 0ustar www-datawww-data# # Author:: Stephen Delano () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::ClientBulkDelete do before(:each) do Chef::Log.logger = Logger.new(StringIO.new) Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::ClientBulkDelete.new @knife.name_args = ["."] @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) @knife.ui.stub!(:confirm).and_return(true) @clients = Hash.new %w{tim dan stephen}.each do |client_name| client = Chef::ApiClient.new() client.name(client_name) client.stub!(:destroy).and_return(true) @clients[client_name] = client end Chef::ApiClient.stub!(:list).and_return(@clients) end describe "run" do it "should get the list of the clients" do Chef::ApiClient.should_receive(:list).and_return(@clients) @knife.run end it "should print the clients you are about to delete" do @knife.run @stdout.string.should match(/#{@knife.ui.list(@clients.keys.sort, :columns_down)}/) end it "should confirm you really want to delete them" do @knife.ui.should_receive(:confirm) @knife.run end it "should delete each client" do @clients.each_value do |c| c.should_receive(:destroy) end @knife.run end it "should only delete clients that match the regex" do @knife.name_args = ["tim"] @clients["tim"].should_receive(:destroy) @clients["stephen"].should_not_receive(:destroy) @clients["dan"].should_not_receive(:destroy) @knife.run end it "should exit if the regex is not provided" do @knife.name_args = [] lambda { @knife.run }.should raise_error(SystemExit) end end end chef-11.8.2/spec/unit/knife/index_rebuild_spec.rb0000644000004100000410000000724212254362222021726 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 Daniel DeLeo # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::IndexRebuild do let(:knife){Chef::Knife::IndexRebuild.new} let(:rest_client){mock(Chef::REST)} let(:stub_rest!) do knife.should_receive(:rest).and_return(rest_client) end before :each do # This keeps the test output clean knife.ui.stub!(:stdout).and_return(StringIO.new) end context "#grab_api_info" do let(:http_not_found_response) do e = Net::HTTPNotFound.new("1.1", 404, "blah") e.stub(:[]).with("x-ops-api-info").and_return(api_header_value) e end let(:http_server_exception) do Net::HTTPServerException.new("404: Not Found", http_not_found_response) end before(:each) do stub_rest! rest_client.stub(:get_rest).and_raise(http_server_exception) end context "against a Chef 11 server" do let(:api_header_value){"flavor=osc;version=11.0.0;erchef=1.2.3"} it "retrieves API information" do knife.grab_api_info.should == {"flavor" => "osc", "version" => "11.0.0", "erchef" => "1.2.3"} end end # Chef 11 context "against a Chef 10 server" do let(:api_header_value){nil} it "finds no API information" do knife.grab_api_info.should == {} end end # Chef 10 end # grab_api_info context "#unsupported_version?" do context "with Chef 11 API metadata" do it "is unsupported" do knife.unsupported_version?({"version" => "11.0.0", "flavor" => "osc", "erchef" => "1.2.3"}).should be_true end it "only truly relies on the version being non-nil" do knife.unsupported_version?({"version" => "1", "flavor" => "osc", "erchef" => "1.2.3"}).should be_true end end context "with Chef 10 API metadata" do it "is supported" do # Chef 10 will have no metadata knife.unsupported_version?({}).should be_false end end end # unsupported_version? context "Simulating a 'knife index rebuild' run" do before :each do knife.should_receive(:grab_api_info).and_return(api_info) server_specific_stubs! end context "against a Chef 11 server" do let(:api_info) do {"flavor" => "osc", "version" => "11.0.0", "erchef" => "1.2.3" } end let(:server_specific_stubs!) do knife.should_receive(:unsupported_server_message).with(api_info) knife.should_receive(:exit).with(1) end it "should not be allowed" do knife.run end end context "against a Chef 10 server" do let(:api_info){ {} } let(:server_specific_stubs!) do stub_rest! rest_client.should_receive(:post_rest).with("/search/reindex", {}).and_return("representative output") knife.should_not_receive(:unsupported_server_message) knife.should_receive(:deprecated_server_message) knife.should_receive(:nag) knife.should_receive(:output).with("representative output") end it "should be allowed" do knife.run end end end end chef-11.8.2/spec/unit/knife/role_bulk_delete_spec.rb0000644000004100000410000000447012254362222022411 0ustar www-datawww-data# # Author:: Stephen Delano () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::RoleBulkDelete do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::RoleBulkDelete.new @knife.config = { :print_after => nil } @knife.name_args = ["."] @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) @knife.ui.stub!(:confirm).and_return(true) @roles = Hash.new %w{dev staging production}.each do |role_name| role = Chef::Role.new() role.name(role_name) role.stub!(:destroy).and_return(true) @roles[role_name] = role end Chef::Role.stub!(:list).and_return(@roles) end describe "run" do it "should get the list of the roles" do Chef::Role.should_receive(:list).and_return(@roles) @knife.run end it "should print the roles you are about to delete" do @knife.run @stdout.string.should match(/#{@knife.ui.list(@roles.keys.sort, :columns_down)}/) end it "should confirm you really want to delete them" do @knife.ui.should_receive(:confirm) @knife.run end it "should delete each role" do @roles.each_value do |r| r.should_receive(:destroy) end @knife.run end it "should only delete roles that match the regex" do @knife.name_args = ["dev"] @roles["dev"].should_receive(:destroy) @roles["staging"].should_not_receive(:destroy) @roles["production"].should_not_receive(:destroy) @knife.run end it "should exit if the regex is not provided" do @knife.name_args = [] lambda { @knife.run }.should raise_error(SystemExit) end end end chef-11.8.2/spec/unit/knife/node_run_list_add_spec.rb0000644000004100000410000001003212254362222022554 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::NodeRunListAdd do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::NodeRunListAdd.new @knife.config = { :after => nil } @knife.name_args = [ "adam", "role[monkey]" ] @knife.stub!(:output).and_return(true) @node = Chef::Node.new() @node.stub!(:save).and_return(true) Chef::Node.stub!(:load).and_return(@node) end describe "run" do it "should load the node" do Chef::Node.should_receive(:load).with("adam") @knife.run end it "should add to the run list" do @knife.run @node.run_list[0].should == 'role[monkey]' end it "should save the node" do @node.should_receive(:save) @knife.run end it "should print the run list" do @knife.should_receive(:output).and_return(true) @knife.run end describe "with -a or --after specified" do it "should add to the run list after the specified entry" do @node.run_list << "role[acorns]" @node.run_list << "role[barn]" @knife.config[:after] = "role[acorns]" @knife.run @node.run_list[0].should == "role[acorns]" @node.run_list[1].should == "role[monkey]" @node.run_list[2].should == "role[barn]" end end describe "with more than one role or recipe" do it "should add to the run list all the entries" do @knife.name_args = [ "adam", "role[monkey],role[duck]" ] @node.run_list << "role[acorns]" @knife.run @node.run_list[0].should == "role[acorns]" @node.run_list[1].should == "role[monkey]" @node.run_list[2].should == "role[duck]" end end describe "with more than one role or recipe with space between items" do it "should add to the run list all the entries" do @knife.name_args = [ "adam", "role[monkey], role[duck]" ] @node.run_list << "role[acorns]" @knife.run @node.run_list[0].should == "role[acorns]" @node.run_list[1].should == "role[monkey]" @node.run_list[2].should == "role[duck]" end end describe "with more than one role or recipe as different arguments" do it "should add to the run list all the entries" do @knife.name_args = [ "adam", "role[monkey]", "role[duck]" ] @node.run_list << "role[acorns]" @knife.run @node.run_list[0].should == "role[acorns]" @node.run_list[1].should == "role[monkey]" @node.run_list[2].should == "role[duck]" end end describe "with more than one role or recipe as different arguments and list separated by comas" do it "should add to the run list all the entries" do @knife.name_args = [ "adam", "role[monkey]", "role[duck],recipe[bird::fly]" ] @node.run_list << "role[acorns]" @knife.run @node.run_list[0].should == "role[acorns]" @node.run_list[1].should == "role[monkey]" @node.run_list[2].should == "role[duck]" end end describe "with one role or recipe but with an extraneous comma" do it "should add to the run list one item" do @knife.name_args = [ "adam", "role[monkey]," ] @node.run_list << "role[acorns]" @knife.run @node.run_list[0].should == "role[acorns]" @node.run_list[1].should == "role[monkey]" end end end end chef-11.8.2/spec/unit/knife/role_edit_spec.rb0000644000004100000410000000430312254362222021052 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::RoleEdit do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::RoleEdit.new @knife.config[:print_after] = nil @knife.name_args = [ "adam" ] @knife.ui.stub!(:output).and_return(true) @role = Chef::Role.new() @role.stub!(:save) Chef::Role.stub!(:load).and_return(@role) @knife.ui.stub!(:edit_data).and_return(@role) @knife.ui.stub!(:msg) end describe "run" do it "should load the role" do Chef::Role.should_receive(:load).with("adam").and_return(@role) @knife.run end it "should edit the role data" do @knife.ui.should_receive(:edit_data).with(@role) @knife.run end it "should save the edited role data" do pansy = Chef::Role.new @role.name("new_role_name") @knife.ui.should_receive(:edit_data).with(@role).and_return(pansy) pansy.should_receive(:save) @knife.run end it "should not save the unedited role data" do pansy = Chef::Role.new @knife.ui.should_receive(:edit_data).with(@role).and_return(pansy) pansy.should_not_receive(:save) @knife.run end it "should not print the role" do @knife.ui.should_not_receive(:output) @knife.run end describe "with -p or --print-after" do it "should pretty print the role, formatted for display" do @knife.config[:print_after] = true @knife.ui.should_receive(:output).with(@role) @knife.run end end end end chef-11.8.2/spec/unit/knife/cookbook_site_share_spec.rb0000644000004100000410000001257612254362222023133 0ustar www-datawww-data# # Author:: Stephen Delano () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/cookbook_uploader' require 'chef/cookbook_site_streaming_uploader' describe Chef::Knife::CookbookSiteShare do before(:each) do @knife = Chef::Knife::CookbookSiteShare.new @knife.name_args = ['cookbook_name', 'AwesomeSausage'] @cookbook = Chef::CookbookVersion.new('cookbook_name') @cookbook_loader = mock('Chef::CookbookLoader') @cookbook_loader.stub!(:cookbook_exists?).and_return(true) @cookbook_loader.stub!(:[]).and_return(@cookbook) Chef::CookbookLoader.stub!(:new).and_return(@cookbook_loader) @cookbook_uploader = Chef::CookbookUploader.new('herpderp', File.join(CHEF_SPEC_DATA, 'cookbooks'), :rest => "norest") Chef::CookbookUploader.stub!(:new).and_return(@cookbook_uploader) @cookbook_uploader.stub!(:validate_cookbooks).and_return(true) Chef::CookbookSiteStreamingUploader.stub!(:create_build_dir).and_return(Dir.mktmpdir) Chef::Mixin::Command.stub(:run_command).and_return(true) @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) end describe 'run' do before(:each) do @knife.stub!(:do_upload).and_return(true) end it 'should should print usage and exit when given no arguments' do @knife.name_args = [] @knife.should_receive(:show_usage) @knife.ui.should_receive(:fatal) lambda { @knife.run }.should raise_error(SystemExit) end it 'should print usage and exit when given only 1 argument' do @knife.name_args = ['cookbook_name'] @knife.should_receive(:show_usage) @knife.ui.should_receive(:fatal) lambda { @knife.run }.should raise_error(SystemExit) end it 'should check if the cookbook exists' do @cookbook_loader.should_receive(:cookbook_exists?) @knife.run end it "should exit and log to error if the cookbook doesn't exist" do @cookbook_loader.stub(:cookbook_exists?).and_return(false) @knife.ui.should_receive(:error) lambda { @knife.run }.should raise_error(SystemExit) end it 'should make a tarball of the cookbook' do Chef::Mixin::Command.should_receive(:run_command) { |args| args[:command].should match /tar -czf/ } @knife.run end it 'should exit and log to error when the tarball creation fails' do Chef::Mixin::Command.stub!(:run_command).and_raise(Chef::Exceptions::Exec) @knife.ui.should_receive(:error) lambda { @knife.run }.should raise_error(SystemExit) end it 'should upload the cookbook and clean up the tarball' do @knife.should_receive(:do_upload) FileUtils.should_receive(:rm_rf) @knife.run end end describe 'do_upload' do before(:each) do @upload_response = mock('Net::HTTPResponse') Chef::CookbookSiteStreamingUploader.stub!(:post).and_return(@upload_response) @stdout = StringIO.new @stderr = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) @knife.ui.stub!(:stderr).and_return(@stderr) File.stub(:open).and_return(true) end it 'should post the cookbook to "http://cookbooks.opscode.com"' do response_text = {:uri => 'http://cookbooks.opscode.com/cookbooks/cookbook_name'}.to_json @upload_response.stub!(:body).and_return(response_text) @upload_response.stub!(:code).and_return(201) Chef::CookbookSiteStreamingUploader.should_receive(:post).with(/cookbooks\.opscode\.com/, anything(), anything(), anything()) @knife.run end it 'should alert the user when a version already exists' do response_text = {:error_messages => ['Version already exists']}.to_json @upload_response.stub!(:body).and_return(response_text) @upload_response.stub!(:code).and_return(409) lambda { @knife.run }.should raise_error(SystemExit) @stderr.string.should match(/ERROR(.+)cookbook already exists/) end it 'should pass any errors on to the user' do response_text = {:error_messages => ["You're holding it wrong"]}.to_json @upload_response.stub!(:body).and_return(response_text) @upload_response.stub!(:code).and_return(403) lambda { @knife.run }.should raise_error(SystemExit) @stderr.string.should match("ERROR(.*)You're holding it wrong") end it 'should print the body if no errors are exposed on failure' do response_text = {:system_error => "Your call was dropped", :reason => "There's a map for that"}.to_json @upload_response.stub!(:body).and_return(response_text) @upload_response.stub!(:code).and_return(500) @knife.ui.should_receive(:error).with(/#{Regexp.escape(response_text)}/)#.ordered @knife.ui.should_receive(:error).with(/Unknown error/)#.ordered lambda { @knife.run }.should raise_error(SystemExit) end end end chef-11.8.2/spec/unit/knife/node_delete_spec.rb0000644000004100000410000000401712254362222021355 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::NodeDelete do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::NodeDelete.new @knife.config = { :print_after => nil } @knife.name_args = [ "adam" ] @knife.stub!(:output).and_return(true) @knife.stub!(:confirm).and_return(true) @node = Chef::Node.new() @node.stub!(:destroy).and_return(true) Chef::Node.stub!(:load).and_return(@node) @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) end describe "run" do it "should confirm that you want to delete" do @knife.should_receive(:confirm) @knife.run end it "should load the node" do Chef::Node.should_receive(:load).with("adam").and_return(@node) @knife.run end it "should delete the node" do @node.should_receive(:destroy).and_return(@node) @knife.run end it "should not print the node" do @knife.should_not_receive(:output).with("poop") @knife.run end describe "with -p or --print-after" do it "should pretty print the node, formatted for display" do @knife.config[:print_after] = true @knife.should_receive(:format_for_display).with(@node).and_return("poop") @knife.should_receive(:output).with("poop") @knife.run end end end end chef-11.8.2/spec/unit/knife/data_bag_create_spec.rb0000644000004100000410000000720512254362222022155 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Author:: Seth Falcon () # Copyright:: Copyright (c) 2009-2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'tempfile' module ChefSpecs class ChefRest attr_reader :args_received def initialize @args_received = [] end def post_rest(*args) @args_received << args end end end describe Chef::Knife::DataBagCreate do before do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::DataBagCreate.new @rest = ChefSpecs::ChefRest.new @knife.stub!(:rest).and_return(@rest) @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) end it "creates a data bag when given one argument" do @knife.name_args = ['sudoing_admins'] @rest.should_receive(:post_rest).with("data", {"name" => "sudoing_admins"}) @knife.ui.should_receive(:info).with("Created data_bag[sudoing_admins]") @knife.run end it "creates a data bag item when given two arguments" do @knife.name_args = ['sudoing_admins', 'ME'] user_supplied_hash = {"login_name" => "alphaomega", "id" => "ME"} data_bag_item = Chef::DataBagItem.from_hash(user_supplied_hash) data_bag_item.data_bag("sudoing_admins") @knife.should_receive(:create_object).and_yield(user_supplied_hash) @rest.should_receive(:post_rest).with("data", {'name' => 'sudoing_admins'}).ordered @rest.should_receive(:post_rest).with("data/sudoing_admins", data_bag_item).ordered @knife.run end describe "encrypted data bag items" do before(:each) do @secret = "abc123SECRET" @plain_data = {"login_name" => "alphaomega", "id" => "ME"} @enc_data = Chef::EncryptedDataBagItem.encrypt_data_bag_item(@plain_data, @secret) @knife.name_args = ['sudoing_admins', 'ME'] @knife.should_receive(:create_object).and_yield(@plain_data) data_bag_item = Chef::DataBagItem.from_hash(@enc_data) data_bag_item.data_bag("sudoing_admins") # Random IV is used each time the data bag item is encrypted, so values # will not be equal if we re-encrypt. Chef::EncryptedDataBagItem.should_receive(:encrypt_data_bag_item).and_return(@enc_data) @rest.should_receive(:post_rest).with("data", {'name' => 'sudoing_admins'}).ordered @rest.should_receive(:post_rest).with("data/sudoing_admins", data_bag_item).ordered @secret_file = Tempfile.new("encrypted_data_bag_secret_file_test") @secret_file.puts(@secret) @secret_file.flush end after do @secret_file.close @secret_file.unlink end it "creates an encrypted data bag item via --secret" do @knife.stub!(:config).and_return({:secret => @secret}) @knife.run end it "creates an encrypted data bag item via --secret_file" do secret_file = Tempfile.new("encrypted_data_bag_secret_file_test") secret_file.puts(@secret) secret_file.flush @knife.stub!(:config).and_return({:secret_file => secret_file.path}) @knife.run end end end chef-11.8.2/spec/unit/knife/cookbook_site_unshare_spec.rb0000644000004100000410000000466412254362222023475 0ustar www-datawww-data# # Author:: Stephen Delano () # Author:: Tim Hinderliter () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::CookbookSiteUnshare do before(:each) do @knife = Chef::Knife::CookbookSiteUnshare.new @knife.name_args = ['cookbook_name'] @knife.stub!(:confirm).and_return(true) @rest = mock('Chef::REST') @rest.stub!(:delete_rest).and_return(true) @knife.stub!(:rest).and_return(@rest) @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) end describe 'run' do describe 'with no cookbook argument' do it 'should print the usage and exit' do @knife.name_args = [] @knife.ui.should_receive(:fatal) @knife.should_receive(:show_usage) lambda { @knife.run }.should raise_error(SystemExit) end end it 'should confirm you want to unshare the cookbook' do @knife.should_receive(:confirm) @knife.run end it 'should send a delete request to the cookbook site' do @rest.should_receive(:delete_rest) @knife.run end it 'should log an error and exit when forbidden' do exception = mock('403 "Forbidden"', :code => '403') @rest.stub!(:delete_rest).and_raise(Net::HTTPServerException.new('403 "Forbidden"', exception)) @knife.ui.should_receive(:error) lambda { @knife.run }.should raise_error(SystemExit) end it 'should re-raise any non-forbidden errors on delete_rest' do exception = mock('500 "Application Error"', :code => '500') @rest.stub(:delete_rest).and_raise(Net::HTTPServerException.new('500 "Application Error"', exception)) lambda { @knife.run }.should raise_error(Net::HTTPServerException) end it 'should log a success message' do @knife.ui.should_receive(:info) @knife.run end end end chef-11.8.2/spec/unit/knife/tag_delete_spec.rb0000644000004100000410000000126112254362222021201 0ustar www-datawww-datarequire 'spec_helper' describe Chef::Knife::TagDelete do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::TagDelete.new @knife.name_args = [ Chef::Config[:node_name], "sadtag" ] @node = Chef::Node.new @node.stub! :save @node.tags << "sadtag" << "happytag" Chef::Node.stub!(:load).and_return @node @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) end describe "run" do it "can delete tags on a node" do @node.tags.should == ["sadtag", "happytag"] @knife.run @node.tags.should == ["happytag"] @stdout.string.should match /deleted.+sadtag/i end end end chef-11.8.2/spec/unit/knife/cookbook_download_spec.rb0000644000004100000410000002230312254362222022601 0ustar www-datawww-data# # Author:: Thomas Bishop () # Copyright:: Copyright (c) 2011 Thomas Bishop # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::CookbookDownload do before(:each) do @knife = Chef::Knife::CookbookDownload.new @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) end describe 'run' do it 'should print usage and exit when a cookbook name is not provided' do @knife.name_args = [] @knife.should_receive(:show_usage) @knife.ui.should_receive(:fatal).with(/must specify a cookbook name/) lambda { @knife.run }.should raise_error(SystemExit) end it 'should exit with a fatal error when there is no cookbook on the server' do @knife.name_args = ['foobar', nil] @knife.should_receive(:determine_version).and_return(nil) @knife.ui.should_receive(:fatal).with('No such cookbook found') lambda { @knife.run }.should raise_error(SystemExit) end describe 'with a cookbook name' do before(:each) do @knife.name_args = ['foobar'] @knife.config[:download_directory] = '/var/tmp/chef' @rest_mock = mock('rest') @knife.stub(:rest).and_return(@rest_mock) @manifest_data = { :recipes => [ {'path' => 'recipes/foo.rb', 'url' => 'http://example.org/files/foo.rb'}, {'path' => 'recipes/bar.rb', 'url' => 'http://example.org/files/bar.rb'} ], :templates => [ {'path' => 'templates/default/foo.erb', 'url' => 'http://example.org/files/foo.erb'}, {'path' => 'templates/default/bar.erb', 'url' => 'http://example.org/files/bar.erb'} ], :attributes => [ {'path' => 'attributes/default.rb', 'url' => 'http://example.org/files/default.rb'} ] } @cookbook_mock = mock('cookbook') @cookbook_mock.stub!(:version).and_return('1.0.0') @cookbook_mock.stub!(:manifest).and_return(@manifest_data) @rest_mock.should_receive(:get_rest).with('cookbooks/foobar/1.0.0'). and_return(@cookbook_mock) end it 'should determine which version if one was not explicitly specified'do @cookbook_mock.stub!(:manifest).and_return({}) @knife.should_receive(:determine_version).and_return('1.0.0') File.should_receive(:exists?).with('/var/tmp/chef/foobar-1.0.0').and_return(false) Chef::CookbookVersion.stub!(:COOKBOOK_SEGEMENTS).and_return([]) @knife.run end describe 'and a version' do before(:each) do @knife.name_args << '1.0.0' @files = @manifest_data.values.map { |v| v.map { |i| i['path'] } }.flatten.uniq @files_mocks = {} @files.map { |f| File.basename(f) }.flatten.uniq.each do |f| @files_mocks[f] = mock("#{f}_mock") @files_mocks[f].stub!(:path).and_return("/var/tmp/#{f}") end end it 'should print an error and exit if the cookbook download directory already exists' do File.should_receive(:exists?).with('/var/tmp/chef/foobar-1.0.0').and_return(true) @knife.ui.should_receive(:fatal).with(/\/var\/tmp\/chef\/foobar-1\.0\.0 exists/i) lambda { @knife.run }.should raise_error(SystemExit) end describe 'when downloading the cookbook' do before(:each) do @files.map { |f| File.dirname(f) }.flatten.uniq.each do |dir| FileUtils.should_receive(:mkdir_p).with("/var/tmp/chef/foobar-1.0.0/#{dir}"). at_least(:once) end @files_mocks.each_pair do |file, mock| @rest_mock.should_receive(:get_rest).with("http://example.org/files/#{file}", true). and_return(mock) end @rest_mock.should_receive(:sign_on_redirect=).with(false).at_least(:once) @files.each do |f| FileUtils.should_receive(:mv). with("/var/tmp/#{File.basename(f)}", "/var/tmp/chef/foobar-1.0.0/#{f}") end end it "should download the cookbook when the cookbook download directory doesn't exist" do File.should_receive(:exists?).with('/var/tmp/chef/foobar-1.0.0').and_return(false) @knife.run ['attributes', 'recipes', 'templates'].each do |segment| @stdout.string.should match /downloading #{segment}/im end @stdout.string.should match /downloading foobar cookbook version 1\.0\.0/im @stdout.string.should match /cookbook downloaded to \/var\/tmp\/chef\/foobar-1\.0\.0/im end describe 'with -f or --force' do it 'should remove the existing the cookbook download directory if it exists' do @knife.config[:force] = true File.should_receive(:exists?).with('/var/tmp/chef/foobar-1.0.0').and_return(true) FileUtils.should_receive(:rm_rf).with('/var/tmp/chef/foobar-1.0.0') @knife.run end end end end end end describe 'determine_version' do it 'should return nil if there are no versions' do @knife.should_receive(:available_versions).and_return(nil) @knife.determine_version.should == nil @knife.version.should == nil end it 'should return and set the version if there is only one version' do @knife.should_receive(:available_versions).at_least(:once).and_return(['1.0.0']) @knife.determine_version.should == '1.0.0' @knife.version.should == '1.0.0' end it 'should ask which version to download and return it if there is more than one' do @knife.should_receive(:available_versions).at_least(:once).and_return(['1.0.0', '2.0.0']) @knife.should_receive(:ask_which_version).and_return('1.0.0') @knife.determine_version.should == '1.0.0' end describe 'with -N or --latest' do it 'should return and set the version to the latest version' do @knife.config[:latest] = true @knife.should_receive(:available_versions).at_least(:once). and_return(['1.0.0', '1.1.0', '2.0.0']) @knife.determine_version @knife.version.to_s.should == '2.0.0' end end end describe 'available_versions' do before(:each) do @knife.cookbook_name = 'foobar' end it 'should return nil if there are no versions' do Chef::CookbookVersion.should_receive(:available_versions). with('foobar'). and_return(nil) @knife.available_versions.should == nil end it 'should return the available versions' do Chef::CookbookVersion.should_receive(:available_versions). with('foobar'). and_return(['1.1.0', '2.0.0', '1.0.0']) @knife.available_versions.should == [Chef::Version.new('1.0.0'), Chef::Version.new('1.1.0'), Chef::Version.new('2.0.0')] end it 'should avoid multiple API calls to the server' do Chef::CookbookVersion.should_receive(:available_versions). once. with('foobar'). and_return(['1.1.0', '2.0.0', '1.0.0']) @knife.available_versions @knife.available_versions end end describe 'ask_which_version' do before(:each) do @knife.cookbook_name = 'foobar' @knife.stub!(:available_versions).and_return(['1.0.0', '1.1.0', '2.0.0']) end it 'should prompt the user to select a version' do prompt = /Which version do you want to download\?.+1\. foobar 1\.0\.0.+2\. foobar 1\.1\.0.+3\. foobar 2\.0\.0.+/m @knife.should_receive(:ask_question).with(prompt).and_return('1') @knife.ask_which_version end it "should set the version to the user's selection" do @knife.should_receive(:ask_question).and_return('1') @knife.ask_which_version @knife.version.should == '1.0.0' end it "should print an error and exit if a version wasn't specified" do @knife.should_receive(:ask_question).and_return('') @knife.ui.should_receive(:error).with(/is not a valid value/i) lambda { @knife.ask_which_version }.should raise_error(SystemExit) end it 'should print an error if an invalid choice was selected' do @knife.should_receive(:ask_question).and_return('100') @knife.ui.should_receive(:error).with(/'100' is not a valid value/i) lambda { @knife.ask_which_version }.should raise_error(SystemExit) end end end chef-11.8.2/spec/unit/knife/environment_from_file_spec.rb0000644000004100000410000000565712254362222023507 0ustar www-datawww-data# # Author:: Stephen Delano () # Author:: Seth Falcon () # Copyright:: Copyright 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' Chef::Knife::EnvironmentFromFile.load_deps describe Chef::Knife::EnvironmentFromFile do before(:each) do @knife = Chef::Knife::EnvironmentFromFile.new @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) @knife.name_args = [ "spec.rb" ] @environment = Chef::Environment.new @environment.name("spec") @environment.description("runs the unit tests") @environment.cookbook_versions({"apt" => "= 1.2.3"}) @environment.stub!(:save).and_return true @knife.loader.stub!(:load_from).and_return @environment end describe "run" do it "loads the environment data from a file and saves it" do @knife.loader.should_receive(:load_from).with('environments', 'spec.rb').and_return(@environment) @environment.should_receive(:save) @knife.run end context "when handling multiple environments" do before(:each) do @env_apple = @environment.dup @env_apple.name("apple") @knife.loader.stub!(:load_from).with("apple.rb").and_return @env_apple end it "loads multiple environments if given" do @knife.name_args = [ "spec.rb", "apple.rb" ] @environment.should_receive(:save).twice @knife.run end it "loads all environments with -a" do File.stub!(:expand_path).with("./environments/*.{json,rb}").and_return("/tmp/environments") Dir.stub!(:glob).with("/tmp/environments").and_return(["spec.rb", "apple.rb"]) @knife.name_args = [] @knife.stub!(:config).and_return({:all => true}) @environment.should_receive(:save).twice @knife.run end end it "should not print the environment" do @knife.should_not_receive(:output) @knife.run end it "should show usage and exit if not filename is provided" do @knife.name_args = [] @knife.ui.should_receive(:fatal) @knife.should_receive(:show_usage) lambda { @knife.run }.should raise_error(SystemExit) end describe "with --print-after" do it "should pretty print the environment, formatted for display" do @knife.config[:print_after] = true @knife.should_receive(:output) @knife.run end end end end chef-11.8.2/spec/unit/knife/tag_create_spec.rb0000644000004100000410000000117212254362222021203 0ustar www-datawww-datarequire 'spec_helper' describe Chef::Knife::TagCreate do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::TagCreate.new @knife.name_args = [ Chef::Config[:node_name], "happytag" ] @node = Chef::Node.new @node.stub! :save Chef::Node.stub!(:load).and_return @node @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) end describe "run" do it "can create tags on a node" do @knife.run @node.tags.should == ["happytag"] @stdout.string.should match /created tags happytag.+node webmonkey.example.com/i end end end chef-11.8.2/spec/unit/knife/user_show_spec.rb0000644000004100000410000000250412254362222021123 0ustar www-datawww-data# # Author:: Steven Danna () # Copyright:: Copyright (c) 2012 Opscode, Inc # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::UserShow do before(:each) do Chef::Knife::UserShow.load_deps @knife = Chef::Knife::UserShow.new @knife.name_args = [ 'my_user' ] @user_mock = mock('user_mock') end it 'loads and displays the user' do Chef::User.should_receive(:load).with('my_user').and_return(@user_mock) @knife.should_receive(:format_for_display).with(@user_mock) @knife.run end it 'prints usage and exits when a user name is not provided' do @knife.name_args = [] @knife.should_receive(:show_usage) @knife.ui.should_receive(:fatal) lambda { @knife.run }.should raise_error(SystemExit) end end chef-11.8.2/spec/unit/knife/user_edit_spec.rb0000644000004100000410000000253512254362222021074 0ustar www-datawww-data# # Author:: Steven Danna () # Copyright:: Copyright (c) 2012 Opscode, Inc # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::UserEdit do before(:each) do Chef::Knife::UserEdit.load_deps @knife = Chef::Knife::UserEdit.new @knife.name_args = [ 'my_user' ] @knife.config[:disable_editing] = true end it 'loads and edits the user' do data = { :name => "my_user" } Chef::User.stub(:load).with("my_user").and_return(data) @knife.should_receive(:edit_data).with(data).and_return(data) @knife.run end it 'prints usage and exits when a user name is not provided' do @knife.name_args = [] @knife.should_receive(:show_usage) @knife.ui.should_receive(:fatal) lambda { @knife.run }.should raise_error(SystemExit) end end chef-11.8.2/spec/unit/knife/user_reregister_spec.rb0000644000004100000410000000350512254362222022320 0ustar www-datawww-data# # Author:: Steven Danna () # Copyright:: Copyright (c) 2012 Opscode, Inc # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::UserReregister do before(:each) do Chef::Knife::UserReregister.load_deps @knife = Chef::Knife::UserReregister.new @knife.name_args = [ 'a_user' ] @user_mock = mock('user_mock', :private_key => "private_key") Chef::User.stub!(:load).and_return(@user_mock) @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) end it 'prints usage and exits when a user name is not provided' do @knife.name_args = [] @knife.should_receive(:show_usage) @knife.ui.should_receive(:fatal) lambda { @knife.run }.should raise_error(SystemExit) end it 'reregisters the user and prints the key' do @user_mock.should_receive(:reregister).and_return(@user_mock) @knife.run @stdout.string.should match( /private_key/ ) end it 'writes the private key to a file when --file is specified' do @user_mock.should_receive(:reregister).and_return(@user_mock) @knife.config[:file] = '/tmp/a_file' filehandle = StringIO.new File.should_receive(:open).with('/tmp/a_file', 'w').and_yield(filehandle) @knife.run filehandle.string.should == "private_key" end end chef-11.8.2/spec/unit/knife/node_show_spec.rb0000644000004100000410000000272412254362222021076 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::NodeShow do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::NodeShow.new @knife.config = { :attribute => nil, :run_list => nil, :environment => nil } @knife.name_args = [ "adam" ] @knife.stub!(:output).and_return(true) @node = Chef::Node.new() Chef::Node.stub!(:load).and_return(@node) end describe "run" do it "should load the node" do Chef::Node.should_receive(:load).with("adam").and_return(@node) @knife.run end it "should pretty print the node, formatted for display" do @knife.should_receive(:format_for_display).with(@node).and_return("poop") @knife.should_receive(:output).with("poop") @knife.run end end end chef-11.8.2/spec/unit/knife/role_list_spec.rb0000644000004100000410000000316412254362222021104 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::RoleList do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::RoleList.new @knife.stub!(:output).and_return(true) @list = { "foo" => "http://example.com/foo", "bar" => "http://example.com/foo" } Chef::Role.stub!(:list).and_return(@list) end describe "run" do it "should list the roles" do Chef::Role.should_receive(:list).and_return(@list) @knife.run end it "should pretty print the list" do Chef::Role.should_receive(:list).and_return(@list) @knife.should_receive(:output).with([ "bar", "foo" ]) @knife.run end describe "with -w or --with-uri" do it "should pretty print the hash" do @knife.config[:with_uri] = true Chef::Role.should_receive(:list).and_return(@list) @knife.should_receive(:output).with(@list) @knife.run end end end end chef-11.8.2/spec/unit/knife/environment_show_spec.rb0000644000004100000410000000330212254362222022506 0ustar www-datawww-data# # Author:: Stephen Delano () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::EnvironmentShow do before(:each) do @knife = Chef::Knife::EnvironmentShow.new @knife.stub!(:msg).and_return true @knife.stub!(:output).and_return true @knife.stub!(:show_usage).and_return true @knife.name_args = [ "production" ] @environment = Chef::Environment.new @environment.name("production") @environment.description("Look at me!") Chef::Environment.stub!(:load).and_return @environment end it "should load the environment" do Chef::Environment.should_receive(:load).with("production") @knife.run end it "should pretty print the environment, formatted for display" do @knife.should_receive(:format_for_display).with(@environment) @knife.should_receive(:output) @knife.run end it "should show usage and exit when no environment name is provided" do @knife.name_args = [] @knife.ui.should_receive(:fatal) @knife.should_receive(:show_usage) lambda { @knife.run }.should raise_error(SystemExit) end end chef-11.8.2/spec/unit/knife/data_bag_from_file_spec.rb0000644000004100000410000001566212254362222022662 0ustar www-datawww-data# # Author:: Seth Falcon () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/data_bag_item' require 'chef/encrypted_data_bag_item' require 'tempfile' require 'json' Chef::Knife::DataBagFromFile.load_deps describe Chef::Knife::DataBagFromFile do before :each do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::DataBagFromFile.new @rest = mock("Chef::REST") @knife.stub!(:rest).and_return(@rest) @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) @tmp_dir = Dir.mktmpdir @db_folder = File.join(@tmp_dir, 'data_bags', 'bag_name') FileUtils.mkdir_p(@db_folder) @db_file = Tempfile.new(["data_bag_from_file_test", ".json"], @db_folder) @db_file2 = Tempfile.new(["data_bag_from_file_test2", ".json"], @db_folder) @db_folder2 = File.join(@tmp_dir, 'data_bags', 'bag_name2') FileUtils.mkdir_p(@db_folder2) @db_file3 = Tempfile.new(["data_bag_from_file_test3", ".json"], @db_folder2) @plain_data = { "id" => "item_name", "greeting" => "hello", "nested" => { "a1" => [1, 2, 3], "a2" => { "b1" => true }} } @db_file.write(@plain_data.to_json) @db_file.flush @knife.instance_variable_set(:@name_args, ['bag_name', @db_file.path]) end # We have to explicitly clean up Tempfile on Windows because it said so. after :each do @db_file.close @db_file2.close @db_file3.close FileUtils.rm_rf(@db_folder) FileUtils.rm_rf(@db_folder2) FileUtils.remove_entry_secure @tmp_dir end it "loads from a file and saves" do @knife.loader.should_receive(:load_from).with("data_bags", 'bag_name', @db_file.path).and_return(@plain_data) dbag = Chef::DataBagItem.new Chef::DataBagItem.stub!(:new).and_return(dbag) dbag.should_receive(:save) @knife.run dbag.data_bag.should == 'bag_name' dbag.raw_data.should == @plain_data end it "loads all from a mutiple files and saves" do @knife.name_args = [ 'bag_name', @db_file.path, @db_file2.path ] @knife.loader.should_receive(:load_from).with("data_bags", 'bag_name', @db_file.path).and_return(@plain_data) @knife.loader.should_receive(:load_from).with("data_bags", 'bag_name', @db_file2.path).and_return(@plain_data) dbag = Chef::DataBagItem.new Chef::DataBagItem.stub!(:new).and_return(dbag) dbag.should_receive(:save).twice @knife.run dbag.data_bag.should == 'bag_name' dbag.raw_data.should == @plain_data end it "loads all from a folder and saves" do dir = File.dirname(@db_file.path) @knife.name_args = [ 'bag_name', @db_folder ] @knife.loader.should_receive(:load_from).with("data_bags", 'bag_name', @db_file.path).and_return(@plain_data) @knife.loader.should_receive(:load_from).with("data_bags", 'bag_name', @db_file2.path).and_return(@plain_data) dbag = Chef::DataBagItem.new Chef::DataBagItem.stub!(:new).and_return(dbag) dbag.should_receive(:save).twice @knife.run end describe "loading all data bags" do before do @pwd = Dir.pwd Dir.chdir(@tmp_dir) end after do Dir.chdir(@pwd) end it "loads all data bags when -a or --all options is provided" do @knife.name_args = [] @knife.stub!(:config).and_return({:all => true}) @knife.loader.should_receive(:load_from).with("data_bags", "bag_name", File.basename(@db_file.path)). and_return(@plain_data) @knife.loader.should_receive(:load_from).with("data_bags", "bag_name", File.basename(@db_file2.path)). and_return(@plain_data) @knife.loader.should_receive(:load_from).with("data_bags", "bag_name2", File.basename(@db_file3.path)). and_return(@plain_data) dbag = Chef::DataBagItem.new Chef::DataBagItem.stub!(:new).and_return(dbag) dbag.should_receive(:save).exactly(3).times @knife.run end it "loads all data bags items when -a or --all options is provided" do @knife.name_args = ["bag_name2"] @knife.stub!(:config).and_return({:all => true}) @knife.loader.should_receive(:load_from).with("data_bags", "bag_name2", File.basename(@db_file3.path)). and_return(@plain_data) dbag = Chef::DataBagItem.new Chef::DataBagItem.stub!(:new).and_return(dbag) dbag.should_receive(:save) @knife.run dbag.data_bag.should == 'bag_name2' dbag.raw_data.should == @plain_data end end describe "encrypted data bag items" do before(:each) do @secret = "abc123SECRET" @enc_data = Chef::EncryptedDataBagItem.encrypt_data_bag_item(@plain_data, @secret) # Random IV is used each time the data bag item is encrypted, so values # will not be equal if we re-encrypt. Chef::EncryptedDataBagItem.should_receive(:encrypt_data_bag_item).and_return(@enc_data) @secret_file = Tempfile.new("encrypted_data_bag_secret_file_test") @secret_file.puts(@secret) @secret_file.flush end after do @secret_file.close @secret_file.unlink end it "encrypts values when given --secret" do @knife.stub!(:config).and_return({:secret => @secret}) @knife.loader.should_receive(:load_from).with("data_bags", "bag_name", @db_file.path).and_return(@plain_data) dbag = Chef::DataBagItem.new Chef::DataBagItem.stub!(:new).and_return(dbag) dbag.should_receive(:save) @knife.run dbag.data_bag.should == 'bag_name' dbag.raw_data.should == @enc_data end it "encrypts values when given --secret_file" do @knife.stub!(:config).and_return({:secret_file => @secret_file.path}) @knife.loader.stub!(:load_from).with("data_bags", 'bag_name', @db_file.path).and_return(@plain_data) dbag = Chef::DataBagItem.new Chef::DataBagItem.stub!(:new).and_return(dbag) dbag.should_receive(:save) @knife.run dbag.data_bag.should == 'bag_name' dbag.raw_data.should == @enc_data end end describe "command line parsing" do it "prints help if given no arguments" do @knife.instance_variable_set(:@name_args, []) lambda { @knife.run }.should raise_error(SystemExit) help_text = "knife data bag from file BAG FILE|FOLDER [FILE|FOLDER..] (options)" help_text_regex = Regexp.new("^#{Regexp.escape(help_text)}") @stdout.string.should match(help_text_regex) end end end chef-11.8.2/spec/unit/knife/client_create_spec.rb0000644000004100000410000000432612254362222021712 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' Chef::Knife::ClientCreate.load_deps describe Chef::Knife::ClientCreate do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::ClientCreate.new @knife.config = { :file => nil } @knife.name_args = [ "adam" ] @client = Chef::ApiClient.new @client.stub!(:save).and_return({ 'private_key' => '' }) @knife.stub!(:edit_data).and_return(@client) @knife.stub!(:puts) Chef::ApiClient.stub!(:new).and_return(@client) @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) end describe "run" do it "should create a new Client" do Chef::ApiClient.should_receive(:new).and_return(@client) @knife.run @stdout.string.should match /created client.+adam/i end it "should set the Client name" do @client.should_receive(:name).with("adam") @knife.run end it "should allow you to edit the data" do @knife.should_receive(:edit_data).with(@client) @knife.run end it "should save the Client" do @client.should_receive(:save) @knife.run end describe "with -f or --file" do it "should write the private key to a file" do @knife.config[:file] = "/tmp/monkeypants" @client.stub!(:save).and_return({ 'private_key' => "woot" }) filehandle = mock("Filehandle") filehandle.should_receive(:print).with('woot') File.should_receive(:open).with("/tmp/monkeypants", "w").and_yield(filehandle) @knife.run end end end end chef-11.8.2/spec/unit/knife/node_bulk_delete_spec.rb0000644000004100000410000000564712254362222022404 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::NodeBulkDelete do before(:each) do Chef::Log.logger = Logger.new(StringIO.new) Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::NodeBulkDelete.new @knife.name_args = ["."] @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) @knife.ui.stub!(:confirm).and_return(true) @nodes = Hash.new %w{adam brent jacob}.each do |node_name| @nodes[node_name] = "http://localhost:4000/nodes/#{node_name}" end end describe "when creating the list of nodes" do it "fetches the node list" do expected = @nodes.inject({}) do |inflatedish, (name, uri)| inflatedish[name] = Chef::Node.new.tap {|n| n.name(name)} inflatedish end Chef::Node.should_receive(:list).and_return(@nodes) # I hate not having == defined for anything :( actual = @knife.all_nodes actual.keys.should =~ expected.keys actual.values.map {|n| n.name }.should =~ %w[adam brent jacob] end end describe "run" do before do @inflatedish_list = @nodes.keys.inject({}) do |nodes_by_name, name| node = Chef::Node.new() node.name(name) node.stub!(:destroy).and_return(true) nodes_by_name[name] = node nodes_by_name end @knife.stub!(:all_nodes).and_return(@inflatedish_list) end it "should print the nodes you are about to delete" do @knife.run @stdout.string.should match(/#{@knife.ui.list(@nodes.keys.sort, :columns_down)}/) end it "should confirm you really want to delete them" do @knife.ui.should_receive(:confirm) @knife.run end it "should delete each node" do @inflatedish_list.each_value do |n| n.should_receive(:destroy) end @knife.run end it "should only delete nodes that match the regex" do @knife.name_args = ['adam'] @inflatedish_list['adam'].should_receive(:destroy) @inflatedish_list['brent'].should_not_receive(:destroy) @inflatedish_list['jacob'].should_not_receive(:destroy) @knife.run end it "should exit if the regex is not provided" do @knife.name_args = [] lambda { @knife.run }.should raise_error(SystemExit) end end end chef-11.8.2/spec/unit/knife/cookbook_metadata_from_file_spec.rb0000644000004100000410000000401612254362222024575 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Matthew Kent () # Copyright:: Copyright (c) 2008 Opscode, Inc. # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::CookbookMetadataFromFile do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @src = File.expand_path(File.join(CHEF_SPEC_DATA, "metadata", "quick_start", "metadata.rb")) @tgt = File.expand_path(File.join(CHEF_SPEC_DATA, "metadata", "quick_start", "metadata.json")) @knife = Chef::Knife::CookbookMetadataFromFile.new @knife.name_args = [ @src ] @knife.stub!(:to_json_pretty).and_return(true) @md = Chef::Cookbook::Metadata.new Chef::Cookbook::Metadata.stub(:new).and_return(@md) $stdout.stub!(:write) end after do if File.exists?(@tgt) File.unlink(@tgt) end end describe "run" do it "should determine cookbook name from path" do @md.should_receive(:name).with() @md.should_receive(:name).with("quick_start") @knife.run end it "should load the metadata source" do @md.should_receive(:from_file).with(@src) @knife.run end it "should write out the metadata to the correct location" do File.should_receive(:open).with(@tgt, "w") @knife.run end it "should generate json from the metadata" do Chef::JSONCompat.should_receive(:to_json_pretty).with(@md) @knife.run end end end chef-11.8.2/spec/unit/knife/role_delete_spec.rb0000644000004100000410000000364312254362222021375 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::RoleDelete do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::RoleDelete.new @knife.config = { :print_after => nil } @knife.name_args = [ "adam" ] @knife.stub!(:output).and_return(true) @knife.stub!(:confirm).and_return(true) @role = Chef::Role.new() @role.stub!(:destroy).and_return(true) Chef::Role.stub!(:load).and_return(@role) @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) end describe "run" do it "should confirm that you want to delete" do @knife.should_receive(:confirm) @knife.run end it "should load the Role" do Chef::Role.should_receive(:load).with("adam").and_return(@role) @knife.run end it "should delete the Role" do @role.should_receive(:destroy).and_return(@role) @knife.run end it "should not print the Role" do @knife.should_not_receive(:output) @knife.run end describe "with -p or --print-after" do it "should pretty print the Role, formatted for display" do @knife.config[:print_after] = true @knife.should_receive(:output) @knife.run end end end end chef-11.8.2/spec/unit/knife/cookbook_delete_spec.rb0000644000004100000410000002115112254362222022234 0ustar www-datawww-data# # Author:: Thomas Bishop () # Copyright:: Copyright (c) 2011 Thomas Bishop # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::CookbookDelete do before(:each) do @knife = Chef::Knife::CookbookDelete.new @knife.name_args = ['foobar'] @knife.cookbook_name = 'foobar' @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) @stderr = StringIO.new @knife.ui.stub!(:stderr).and_return(@stderr) end describe 'run' do it 'should print usage and exit when a cookbook name is not provided' do @knife.name_args = [] @knife.should_receive(:show_usage) @knife.ui.should_receive(:fatal) lambda { @knife.run }.should raise_error(SystemExit) end describe 'when specifying a cookbook name' do it 'should delete the cookbook without a specific version' do @knife.should_receive(:delete_without_explicit_version) @knife.run end describe 'and a version' do it 'should delete the specific version of the cookbook' do @knife.name_args << '1.0.0' @knife.should_receive(:delete_explicit_version) @knife.run end end describe 'with -a or --all' do it 'should delete all versions of the cookbook' do @knife.config[:all] = true @knife.should_receive(:delete_all_versions) @knife.run end end describe 'with -p or --purge' do it 'should prompt to purge the files' do @knife.config[:purge] = true @knife.should_receive(:confirm). with(/.+Are you sure you want to purge files.+/) @knife.should_receive(:delete_without_explicit_version) @knife.run end end end end describe 'delete_explicit_version' do it 'should delete the specific cookbook version' do @knife.cookbook_name = 'foobar' @knife.version = '1.0.0' @knife.should_receive(:delete_object).with(Chef::CookbookVersion, 'foobar version 1.0.0', 'cookbook').and_yield() @knife.should_receive(:delete_request).with('cookbooks/foobar/1.0.0') @knife.delete_explicit_version end end describe 'delete_all_versions' do it 'should prompt to delete all versions of the cookbook' do @knife.cookbook_name = 'foobar' @knife.should_receive(:confirm).with('Do you really want to delete all versions of foobar') @knife.should_receive(:delete_all_without_confirmation) @knife.delete_all_versions end end describe 'delete_all_without_confirmation' do it 'should delete all versions without confirmation' do versions = ['1.0.0', '1.1.0'] @knife.should_receive(:available_versions).and_return(versions) versions.each do |v| @knife.should_receive(:delete_version_without_confirmation).with(v) end @knife.delete_all_without_confirmation end end describe 'delete_without_explicit_version' do it 'should exit if there are no available versions' do @knife.should_receive(:available_versions).and_return(nil) lambda { @knife.delete_without_explicit_version }.should raise_error(SystemExit) end it 'should delete the version if only one is found' do @knife.should_receive(:available_versions).at_least(:once).and_return(['1.0.0']) @knife.should_receive(:delete_explicit_version) @knife.delete_without_explicit_version end it 'should ask which version(s) to delete if multiple are found' do @knife.should_receive(:available_versions).at_least(:once).and_return(['1.0.0', '1.1.0']) @knife.should_receive(:ask_which_versions_to_delete).and_return(['1.0.0', '1.1.0']) @knife.should_receive(:delete_versions_without_confirmation).with(['1.0.0', '1.1.0']) @knife.delete_without_explicit_version end end describe 'available_versions' do before(:each) do @rest_mock = mock('rest') @knife.should_receive(:rest).and_return(@rest_mock) @cookbook_data = { 'foobar' => { 'versions' => [{'version' => '1.0.0'}, {'version' => '1.1.0'}, {'version' => '2.0.0'} ]} } end it 'should return the list of versions of the cookbook' do @rest_mock.should_receive(:get_rest).with('cookbooks/foobar').and_return(@cookbook_data) @knife.available_versions.should == ['1.0.0', '1.1.0', '2.0.0'] end it 'should raise if an error other than HTTP 404 is returned' do exception = Net::HTTPServerException.new('500 Internal Server Error', '500') @rest_mock.should_receive(:get_rest).and_raise(exception) lambda { @knife.available_versions }.should raise_error Net::HTTPServerException end describe "if the cookbook can't be found" do before(:each) do @rest_mock.should_receive(:get_rest). and_raise(Net::HTTPServerException.new('404 Not Found', '404')) end it 'should print an error' do @knife.available_versions @stderr.string.should match /error.+cannot find a cookbook named foobar/i end it 'should return nil' do @knife.available_versions.should == nil end end end describe 'ask_which_version_to_delete' do before(:each) do @knife.stub!(:available_versions).and_return(['1.0.0', '1.1.0', '2.0.0']) end it 'should prompt the user to select a version' do prompt = /Which version\(s\) do you want to delete\?.+1\. foobar 1\.0\.0.+2\. foobar 1\.1\.0.+3\. foobar 2\.0\.0.+4\. All versions.+/m @knife.should_receive(:ask_question).with(prompt).and_return('1') @knife.ask_which_versions_to_delete end it "should print an error and exit if a version wasn't specified" do @knife.should_receive(:ask_question).and_return('') @knife.ui.should_receive(:error).with(/no versions specified/i) lambda { @knife.ask_which_versions_to_delete }.should raise_error(SystemExit) end it 'should print an error if an invalid choice was selected' do @knife.should_receive(:ask_question).and_return('100') @knife.ui.should_receive(:error).with(/100 is not a valid choice/i) @knife.ask_which_versions_to_delete end it 'should return the selected versions' do @knife.should_receive(:ask_question).and_return('1, 3') @knife.ask_which_versions_to_delete.should == ['1.0.0', '2.0.0'] end it "should return all of the versions if 'all' was selected" do @knife.should_receive(:ask_question).and_return('4') @knife.ask_which_versions_to_delete.should == [:all] end end describe 'delete_version_without_confirmation' do it 'should delete the cookbook version' do @knife.should_receive(:delete_request).with('cookbooks/foobar/1.0.0') @knife.delete_version_without_confirmation('1.0.0') end it 'should output that the cookbook was deleted' do @knife.stub!(:delete_request) @knife.delete_version_without_confirmation('1.0.0') @stdout.string.should match /deleted cookbook\[foobar\]\[1.0.0\]/im end describe 'with --print-after' do it 'should display the cookbook data' do object = '' @knife.config[:print_after] = true @knife.stub!(:delete_request).and_return(object) @knife.should_receive(:format_for_display).with(object) @knife.delete_version_without_confirmation('1.0.0') end end end describe 'delete_versions_without_confirmation' do it 'should delete each version without confirmation' do versions = ['1.0.0', '1.1.0'] versions.each do |v| @knife.should_receive(:delete_version_without_confirmation).with(v) end @knife.delete_versions_without_confirmation(versions) end describe 'with -a or --all' do it 'should delete all versions without confirmation' do versions = [:all] @knife.should_receive(:delete_all_without_confirmation) @knife.delete_versions_without_confirmation(versions) end end end end chef-11.8.2/spec/unit/knife/bootstrap_spec.rb0000644000004100000410000003463712254362222021136 0ustar www-datawww-data# # Author:: Ian Meyer () # Copyright:: Copyright (c) 2010 Ian Meyer # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' Chef::Knife::Bootstrap.load_deps require 'net/ssh' describe Chef::Knife::Bootstrap do before(:each) do Chef::Log.logger = Logger.new(StringIO.new) @knife = Chef::Knife::Bootstrap.new # Merge default settings in. @knife.merge_configs @knife.config[:template_file] = File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "test.erb")) @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) @stderr = StringIO.new @knife.ui.stub!(:stderr).and_return(@stderr) end it "should return a name of default bootstrap template" do @knife.find_template.should be_a_kind_of(String) end it "should error if template can not be found" do @knife.config[:template_file] = false @knife.config[:distro] = 'penultimate' lambda { @knife.find_template }.should raise_error end it "should look for templates early in the run" do File.stub(:exists?).and_return(true) @knife.name_args = ['shatner'] @knife.stub!(:read_template).and_return("") @knife.stub!(:knife_ssh).and_return(true) @knife_ssh = @knife.knife_ssh @knife.should_receive(:find_template).ordered @knife.should_receive(:knife_ssh).ordered @knife_ssh.should_receive(:run) # rspec appears to keep order per object @knife.run end it "should load the specified template" do @knife.config[:distro] = 'fedora13-gems' lambda { @knife.find_template }.should_not raise_error end it "should load the specified template from a Ruby gem" do @knife.config[:template_file] = false Gem.stub(:find_files).and_return(["/Users/schisamo/.rvm/gems/ruby-1.9.2-p180@chef-0.10/gems/knife-windows-0.5.4/lib/chef/knife/bootstrap/fake-bootstrap-template.erb"]) File.stub(:exists?).and_return(true) IO.stub(:read).and_return('random content') @knife.config[:distro] = 'fake-bootstrap-template' lambda { @knife.find_template }.should_not raise_error end it "should return an empty run_list" do @knife.instance_variable_set("@template_file", @knife.config[:template_file]) template_string = @knife.read_template @knife.render_template(template_string).should == '{"run_list":[]}' end it "should have role[base] in the run_list" do @knife.instance_variable_set("@template_file", @knife.config[:template_file]) template_string = @knife.read_template @knife.parse_options(["-r","role[base]"]) @knife.render_template(template_string).should == '{"run_list":["role[base]"]}' end it "should have role[base] and recipe[cupcakes] in the run_list" do @knife.instance_variable_set("@template_file", @knife.config[:template_file]) template_string = @knife.read_template @knife.parse_options(["-r", "role[base],recipe[cupcakes]"]) @knife.render_template(template_string).should == '{"run_list":["role[base]","recipe[cupcakes]"]}' end it "should have foo => {bar => baz} in the first_boot" do @knife.instance_variable_set("@template_file", @knife.config[:template_file]) template_string = @knife.read_template @knife.parse_options(["-j", '{"foo":{"bar":"baz"}}']) expected_hash = Yajl::Parser.new.parse('{"foo":{"bar":"baz"},"run_list":[]}') actual_hash = Yajl::Parser.new.parse(@knife.render_template(template_string)) actual_hash.should == expected_hash end it "should create a hint file when told to" do @knife.config[:template_file] = File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "test-hints.erb")) @knife.instance_variable_set("@template_file", @knife.config[:template_file]) template_string = @knife.read_template @knife.parse_options(["--hint", "openstack"]) @knife.render_template(template_string).should match /\/etc\/chef\/ohai\/hints\/openstack.json/ end it "should populate a hint file with JSON when given a file to read" do @knife.stub(:find_template).and_return(true) @knife.config[:template_file] = File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "test-hints.erb")) ::File.stub!(:read).and_return('{ "foo" : "bar" }') @knife.instance_variable_set("@template_file", @knife.config[:template_file]) template_string = @knife.read_template @knife.stub!(:read_template).and_return('{ "foo" : "bar" }') @knife.parse_options(["--hint", "openstack=hints/openstack.json"]) @knife.render_template(template_string).should match /\{\"foo\":\"bar\"\}/ end it "should take the node name from ARGV" do @knife.name_args = ['barf'] @knife.name_args.first.should == "barf" end describe "specifying no_proxy with various entries" do subject(:knife) { described_class.new } let(:options){ ["--bootstrap-no-proxy", setting] } let(:template_file) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "no_proxy.erb")) } let(:rendered_template) do knife.instance_variable_set("@template_file", template_file) knife.parse_options(options) template_string = knife.read_template knife.render_template(template_string) end context "via --bootstrap-no-proxy" do let(:setting) { "api.opscode.com" } it "renders the client.rb with a single FQDN no_proxy entry" do rendered_template.should match(%r{.*no_proxy\s*"api.opscode.com".*}) end end context "via --bootstrap-no-proxy multiple" do let(:setting) { "api.opscode.com,172.16.10.*" } it "renders the client.rb with comma-separated FQDN and wildcard IP address no_proxy entries" do rendered_template.should match(%r{.*no_proxy\s*"api.opscode.com,172.16.10.\*".*}) end end end describe "specifying the encrypted data bag secret key" do subject(:knife) { described_class.new } let(:secret) { "supersekret" } let(:secret_file) { File.join(CHEF_SPEC_DATA, 'bootstrap', 'encrypted_data_bag_secret') } let(:options) { [] } let(:template_file) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "secret.erb")) } let(:rendered_template) do knife.instance_variable_set("@template_file", template_file) knife.parse_options(options) template_string = knife.read_template knife.render_template(template_string) end context "via --secret" do let(:options){ ["--secret", secret] } it "creates a secret file" do rendered_template.should match(%r{#{secret}}) end it "renders the client.rb with an encrypted_data_bag_secret entry" do rendered_template.should match(%r{encrypted_data_bag_secret\s*"/etc/chef/encrypted_data_bag_secret"}) end end context "via --secret-file" do let(:options) { ["--secret-file", secret_file] } let(:secret) { IO.read(secret_file) } it "creates a secret file" do rendered_template.should match(%r{#{secret}}) end it "renders the client.rb with an encrypted_data_bag_secret entry" do rendered_template.should match(%r{encrypted_data_bag_secret\s*"/etc/chef/encrypted_data_bag_secret"}) end end context "via Chef::Config[:encrypted_data_bag_secret]" do before(:each) { Chef::Config[:encrypted_data_bag_secret] = secret_file } let(:secret) { IO.read(secret_file) } it "creates a secret file" do rendered_template.should match(%r{#{secret}}) end it "renders the client.rb with an encrypted_data_bag_secret entry" do rendered_template.should match(%r{encrypted_data_bag_secret\s*"/etc/chef/encrypted_data_bag_secret"}) end end end describe "when configuring the underlying knife ssh command" do context "from the command line" do before do @knife.name_args = ["foo.example.com"] @knife.config[:ssh_user] = "rooty" @knife.config[:ssh_port] = "4001" @knife.config[:ssh_password] = "open_sesame" Chef::Config[:knife][:ssh_user] = nil Chef::Config[:knife][:ssh_port] = nil @knife.config[:forward_agent] = true @knife.config[:identity_file] = "~/.ssh/me.rsa" @knife.stub!(:read_template).and_return("") @knife_ssh = @knife.knife_ssh end it "configures the hostname" do @knife_ssh.name_args.first.should == "foo.example.com" end it "configures the ssh user" do @knife_ssh.config[:ssh_user].should == 'rooty' end it "configures the ssh password" do @knife_ssh.config[:ssh_password].should == 'open_sesame' end it "configures the ssh port" do @knife_ssh.config[:ssh_port].should == '4001' end it "configures the ssh agent forwarding" do @knife_ssh.config[:forward_agent].should == true end it "configures the ssh identity file" do @knife_ssh.config[:identity_file].should == '~/.ssh/me.rsa' end end context "validating use_sudo_password" do before do @knife.config[:distro] = "ubuntu" @knife.config[:ssh_password] = "password" @knife.stub(:read_template).and_return(IO.read(@knife.find_template).chomp) end it "use_sudo_password contains description and long params for help" do @knife.options.should have_key(:use_sudo_password) \ and @knife.options[:use_sudo_password][:description].to_s.should_not == ''\ and @knife.options[:use_sudo_password][:long].to_s.should_not == '' end it "uses the password from --ssh-password for sudo when --use-sudo-password is set" do @knife.config[:use_sudo] = true @knife.config[:use_sudo_password] = true @knife.ssh_command.should include("echo \'#{@knife.config[:ssh_password]}\' | sudo -S") end it "should not honor --use-sudo-password when --use-sudo is not set" do @knife.config[:use_sudo] = false @knife.config[:use_sudo_password] = true @knife.ssh_command.should_not include("echo #{@knife.config[:ssh_password]} | sudo -S") end end context "from the knife config file" do before do @knife.name_args = ["config.example.com"] @knife.config[:ssh_user] = nil @knife.config[:ssh_port] = nil @knife.config[:ssh_gateway] = nil @knife.config[:forward_agent] = nil @knife.config[:identity_file] = nil @knife.config[:host_key_verify] = nil Chef::Config[:knife][:ssh_user] = "curiosity" Chef::Config[:knife][:ssh_port] = "2430" Chef::Config[:knife][:forward_agent] = true Chef::Config[:knife][:identity_file] = "~/.ssh/you.rsa" Chef::Config[:knife][:ssh_gateway] = "towel.blinkenlights.nl" Chef::Config[:knife][:host_key_verify] = true @knife.stub!(:read_template).and_return("") @knife_ssh = @knife.knife_ssh end it "configures the ssh user" do @knife_ssh.config[:ssh_user].should == 'curiosity' end it "configures the ssh port" do @knife_ssh.config[:ssh_port].should == '2430' end it "configures the ssh agent forwarding" do @knife_ssh.config[:forward_agent].should == true end it "configures the ssh identity file" do @knife_ssh.config[:identity_file].should == '~/.ssh/you.rsa' end it "configures the ssh gateway" do @knife_ssh.config[:ssh_gateway].should == 'towel.blinkenlights.nl' end it "configures the host key verify mode" do @knife_ssh.config[:host_key_verify].should == true end end describe "when falling back to password auth when host key auth fails" do before do @knife.name_args = ["foo.example.com"] @knife.config[:ssh_user] = "rooty" @knife.config[:identity_file] = "~/.ssh/me.rsa" @knife.stub!(:read_template).and_return("") @knife_ssh = @knife.knife_ssh end it "prompts the user for a password " do @knife.stub!(:knife_ssh).and_return(@knife_ssh) @knife_ssh.stub!(:get_password).and_return('typed_in_password') alternate_knife_ssh = @knife.knife_ssh_with_password_auth alternate_knife_ssh.config[:ssh_password].should == 'typed_in_password' end it "configures knife not to use the identity file that didn't work previously" do @knife.stub!(:knife_ssh).and_return(@knife_ssh) @knife_ssh.stub!(:get_password).and_return('typed_in_password') alternate_knife_ssh = @knife.knife_ssh_with_password_auth alternate_knife_ssh.config[:identity_file].should be_nil end end end describe "when running the bootstrap" do before do @knife.name_args = ["foo.example.com"] @knife.config[:ssh_user] = "rooty" @knife.config[:identity_file] = "~/.ssh/me.rsa" @knife.stub!(:read_template).and_return("") @knife_ssh = @knife.knife_ssh @knife.stub!(:knife_ssh).and_return(@knife_ssh) end it "verifies that a server to bootstrap was given as a command line arg" do @knife.name_args = nil lambda { @knife.run }.should raise_error(SystemExit) @stderr.string.should match /ERROR:.+FQDN or ip/ end it "configures the underlying ssh command and then runs it" do @knife_ssh.should_receive(:run) @knife.run end it "falls back to password based auth when auth fails the first time" do @knife.stub!(:puts) @fallback_knife_ssh = @knife_ssh.dup @knife_ssh.should_receive(:run).and_raise(Net::SSH::AuthenticationFailed.new("no ssh for you")) @knife.stub!(:knife_ssh_with_password_auth).and_return(@fallback_knife_ssh) @fallback_knife_ssh.should_receive(:run) @knife.run end context "Chef::Config[:encrypted_data_bag_secret] is set" do let(:secret_file) { File.join(CHEF_SPEC_DATA, 'bootstrap', 'encrypted_data_bag_secret') } before { Chef::Config[:encrypted_data_bag_secret] = secret_file } it "warns the configuration option is deprecated" do @knife_ssh.should_receive(:run) @knife.ui.should_receive(:warn).at_least(3).times @knife.run end end end end chef-11.8.2/spec/unit/knife/data_bag_edit_spec.rb0000644000004100000410000000655212254362222021643 0ustar www-datawww-data# # Author:: Seth Falcon () # Copyright:: Copyright 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'tempfile' describe Chef::Knife::DataBagEdit do before do @plain_data = {"login_name" => "alphaomega", "id" => "item_name"} @edited_data = { "login_name" => "rho", "id" => "item_name", "new_key" => "new_value" } Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::DataBagEdit.new @rest = mock('chef-rest-mock') @knife.stub!(:rest).and_return(@rest) @stdout = StringIO.new @knife.stub!(:stdout).and_return(@stdout) @log = Chef::Log @knife.name_args = ['bag_name', 'item_name'] end it "requires data bag and item arguments" do @knife.name_args = [] lambda { @knife.run }.should raise_error(SystemExit) @stdout.string.should match(/^You must supply the data bag and an item to edit/) end it "saves edits on a data bag item" do Chef::DataBagItem.stub!(:load).with('bag_name', 'item_name').and_return(@plain_data) @knife.should_receive(:edit_data).with(@plain_data).and_return(@edited_data) @rest.should_receive(:put_rest).with("data/bag_name/item_name", @edited_data).ordered @knife.run end describe "encrypted data bag items" do before(:each) do @secret = "abc123SECRET" @enc_data = Chef::EncryptedDataBagItem.encrypt_data_bag_item(@plain_data, @secret) @enc_edited_data = Chef::EncryptedDataBagItem.encrypt_data_bag_item(@edited_data, @secret) Chef::DataBagItem.stub!(:load).with('bag_name', 'item_name').and_return(@enc_data) # Random IV is used each time the data bag item is encrypted, so values # will not be equal if we encrypt same value twice. Chef::EncryptedDataBagItem.should_receive(:encrypt_data_bag_item).and_return(@enc_edited_data) @secret_file = Tempfile.new("encrypted_data_bag_secret_file_test") @secret_file.puts(@secret) @secret_file.flush end after do @secret_file.close @secret_file.unlink end it "decrypts and encrypts via --secret" do @knife.stub!(:config).and_return({:secret => @secret}) @knife.should_receive(:edit_data).with(@plain_data).and_return(@edited_data) @rest.should_receive(:put_rest).with("data/bag_name/item_name", @enc_edited_data).ordered @knife.run end it "decrypts and encrypts via --secret_file" do @knife.stub!(:config).and_return({:secret_file => @secret_file.path}) @knife.should_receive(:edit_data).with(@plain_data).and_return(@edited_data) @rest.should_receive(:put_rest).with("data/bag_name/item_name", @enc_edited_data).ordered @knife.run end end end chef-11.8.2/spec/unit/knife/environment_list_spec.rb0000644000004100000410000000340612254362222022506 0ustar www-datawww-data# # Author:: Stephen Delano () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::EnvironmentList do before(:each) do @knife = Chef::Knife::EnvironmentList.new @knife.stub!(:msg).and_return true @knife.stub!(:output).and_return true @knife.stub!(:show_usage).and_return true @environments = { "production" => "http://localhost:4000/environments/production", "development" => "http://localhost:4000/environments/development", "testing" => "http://localhost:4000/environments/testing" } Chef::Environment.stub!(:list).and_return @environments end it "should make an api call to list the environments" do Chef::Environment.should_receive(:list) @knife.run end it "should print the environment names in a sorted list" do names = @environments.keys.sort { |a,b| a <=> b } @knife.should_receive(:output).with(names) @knife.run end describe "with --with-uri" do it "should print and unsorted list of the environments and their URIs" do @knife.config[:with_uri] = true @knife.should_receive(:output).with(@environments) @knife.run end end end chef-11.8.2/spec/unit/knife/node_run_list_remove_spec.rb0000644000004100000410000000434412254362222023332 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::NodeRunListRemove do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::NodeRunListRemove.new @knife.config[:print_after] = nil @knife.name_args = [ "adam", "role[monkey]" ] @node = Chef::Node.new() @node.name("knifetest-node") @node.run_list << "role[monkey]" @node.stub!(:save).and_return(true) @knife.ui.stub!(:output).and_return(true) @knife.ui.stub!(:confirm).and_return(true) Chef::Node.stub!(:load).and_return(@node) end describe "run" do it "should load the node" do Chef::Node.should_receive(:load).with("adam").and_return(@node) @knife.run end it "should remove the item from the run list" do @knife.run @node.run_list[0].should_not == 'role[monkey]' end it "should save the node" do @node.should_receive(:save).and_return(true) @knife.run end it "should print the run list" do @knife.config[:print_after] = true @knife.ui.should_receive(:output).with({ "knifetest-node" => { 'run_list' => [] } }) @knife.run end describe "run with a list of roles and recipes" do it "should remove the items from the run list" do @node.run_list << 'role[monkey]' @node.run_list << 'recipe[duck::type]' @knife.name_args = [ 'adam', 'role[monkey],recipe[duck::type]' ] @knife.run @node.run_list.should_not include('role[monkey]') @node.run_list.should_not include('recipe[duck::type]') end end end end chef-11.8.2/spec/unit/knife/client_show_spec.rb0000644000004100000410000000254512254362222021430 0ustar www-datawww-data# # Author:: Thomas Bishop () # Copyright:: Copyright (c) 2011 Thomas Bishop # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::ClientShow do before(:each) do @knife = Chef::Knife::ClientShow.new @knife.name_args = [ 'adam' ] @client_mock = mock('client_mock') end describe 'run' do it 'should list the client' do Chef::ApiClient.should_receive(:load).with('adam').and_return(@client_mock) @knife.should_receive(:format_for_display).with(@client_mock) @knife.run end it 'should print usage and exit when a client name is not provided' do @knife.name_args = [] @knife.should_receive(:show_usage) @knife.ui.should_receive(:fatal) lambda { @knife.run }.should raise_error(SystemExit) end end end chef-11.8.2/spec/unit/knife/node_run_list_set_spec.rb0000644000004100000410000001072512254362222022630 0ustar www-datawww-data# # Author:: Mike Fiedler () # Copyright:: Copyright (c) 2013 Mike Fiedler # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::NodeRunListSet do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::NodeRunListSet.new @knife.config = {} @knife.name_args = [ "adam", "role[monkey]" ] @knife.stub!(:output).and_return(true) @node = Chef::Node.new() @node.stub!(:save).and_return(true) Chef::Node.stub!(:load).and_return(@node) end describe "run" do it "should load the node" do Chef::Node.should_receive(:load).with("adam") @knife.run end it "should set the run list" do @knife.run @node.run_list[0].should == 'role[monkey]' end it "should save the node" do @node.should_receive(:save) @knife.run end it "should print the run list" do @knife.should_receive(:output).and_return(true) @knife.run end describe "with more than one role or recipe" do it "should set the run list to all the entries" do @knife.name_args = [ "adam", "role[monkey],role[duck]" ] @knife.run @node.run_list[0].should == "role[monkey]" @node.run_list[1].should == "role[duck]" end end describe "with more than one role or recipe with space between items" do it "should set the run list to all the entries" do @knife.name_args = [ "adam", "role[monkey], role[duck]" ] @knife.run @node.run_list[0].should == "role[monkey]" @node.run_list[1].should == "role[duck]" end end describe "with more than one role or recipe as different arguments" do it "should set the run list to all the entries" do @knife.name_args = [ "adam", "role[monkey]", "role[duck]" ] @knife.run @node.run_list[0].should == "role[monkey]" @node.run_list[1].should == "role[duck]" end end describe "with more than one role or recipe as different arguments and list separated by comas" do it "should add to the run list all the entries" do @knife.name_args = [ "adam", "role[monkey]", "role[duck],recipe[bird::fly]" ] @knife.run @node.run_list[0].should == "role[monkey]" @node.run_list[1].should == "role[duck]" end end describe "with one role or recipe but with an extraneous comma" do it "should add to the run list one item" do @knife.name_args = [ "adam", "role[monkey]," ] @knife.run @node.run_list[0].should == "role[monkey]" end end describe "with an existing run list" do it "should overwrite any existing run list items" do @node.run_list << "role[acorns]" @node.run_list << "role[zebras]" @node.run_list[0].should == "role[acorns]" @node.run_list[1].should == "role[zebras]" @node.run_list.run_list_items.size.should == 2 @knife.name_args = [ "adam", "role[monkey]", "role[duck]" ] @knife.run @node.run_list[0].should == "role[monkey]" @node.run_list[1].should == "role[duck]" @node.run_list.run_list_items.size.should == 2 end end describe "with no role or recipe" do # Set up outputs for inspection later before(:each) do @stdout = StringIO.new @stderr = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) @knife.ui.stub!(:stderr).and_return(@stderr) end it "should exit" do @knife.name_args = [ "adam" ] lambda { @knife.run }.should raise_error SystemExit end it "should show the user" do @knife.name_args = [ "adam" ] begin ; @knife.run ; rescue SystemExit ; end @stdout.string.should eq "USAGE: knife node run_list set NODE ENTRIES (options)\n" @stderr.string.should eq "FATAL: You must supply both a node name and a run list.\n" end end end end chef-11.8.2/spec/unit/knife/configure_spec.rb0000644000004100000410000002500312254362222021065 0ustar www-datawww-datarequire 'spec_helper' describe Chef::Knife::Configure do before do Chef::Log.logger = Logger.new(StringIO.new) Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::Configure.new @rest_client = mock("null rest client", :post_rest => { :result => :true }) @knife.stub!(:rest).and_return(@rest_client) @out = StringIO.new @knife.ui.stub!(:stdout).and_return(@out) @knife.config[:config_file] = '/home/you/.chef/knife.rb' @in = StringIO.new("\n" * 7) @knife.ui.stub!(:stdin).and_return(@in) @err = StringIO.new @knife.ui.stub!(:stderr).and_return(@err) Ohai::System.stub!(:new).and_return(ohai) end let(:fqdn) { "foo.example.org" } let(:ohai) do o = {} o.stub(:require_plugin) o[:fqdn] = fqdn o end let(:default_admin_key) { "/etc/chef-server/admin.pem" } let(:default_admin_key_win32) { File.expand_path(default_admin_key) } let(:default_validator_key) { "/etc/chef-server/chef-validator.pem" } let(:default_validator_key_win32) { File.expand_path(default_validator_key) } let(:default_server_url) { "https://#{fqdn}:443" } it "asks the user for the URL of the chef server" do @knife.ask_user_for_config @out.string.should match(Regexp.escape("Please enter the chef server URL: [#{default_server_url}]")) @knife.chef_server.should == default_server_url end it "asks the user for the clientname they want for the new client if -i is specified" do @knife.config[:initial] = true Etc.stub!(:getlogin).and_return("a-new-user") @knife.ask_user_for_config @out.string.should match(Regexp.escape("Please enter a name for the new user: [a-new-user]")) @knife.new_client_name.should == Etc.getlogin end it "should not ask the user for the clientname they want for the new client if -i and --node_name are specified" do @knife.config[:initial] = true @knife.config[:node_name] = 'testnode' Etc.stub!(:getlogin).and_return("a-new-user") @knife.ask_user_for_config @out.string.should_not match(Regexp.escape("Please enter a name for the new user")) @knife.new_client_name.should == 'testnode' end it "asks the user for the existing API username or clientname if -i is not specified" do Etc.stub!(:getlogin).and_return("a-new-user") @knife.ask_user_for_config @out.string.should match(Regexp.escape("Please enter an existing username or clientname for the API: [a-new-user]")) @knife.new_client_name.should == Etc.getlogin end it "asks the user for the existing admin client's name if -i is specified" do @knife.config[:initial] = true @knife.ask_user_for_config @out.string.should match(Regexp.escape("Please enter the existing admin name: [admin]")) @knife.admin_client_name.should == 'admin' end it "should not ask the user for the existing admin client's name if -i and --admin-client_name are specified" do @knife.config[:initial] = true @knife.config[:admin_client_name] = 'my-webui' @knife.ask_user_for_config @out.string.should_not match(Regexp.escape("Please enter the existing admin:")) @knife.admin_client_name.should == 'my-webui' end it "should not ask the user for the existing admin client's name if -i is not specified" do @knife.ask_user_for_config @out.string.should_not match(Regexp.escape("Please enter the existing admin: [admin]")) @knife.admin_client_name.should_not == 'admin' end it "asks the user for the location of the existing admin key if -i is specified" do @knife.config[:initial] = true @knife.ask_user_for_config @out.string.should match(Regexp.escape("Please enter the location of the existing admin's private key: [#{default_admin_key}]")) if windows? @knife.admin_client_key.capitalize.should == default_admin_key_win32.capitalize else @knife.admin_client_key.should == default_admin_key end end it "should not ask the user for the location of the existing admin key if -i and --admin_client_key are specified" do @knife.config[:initial] = true @knife.config[:admin_client_key] = '/home/you/.chef/my-webui.pem' @knife.ask_user_for_config @out.string.should_not match(Regexp.escape("Please enter the location of the existing admin client's private key:")) if windows? @knife.admin_client_key.should match %r{^[A-Za-z]:/home/you/\.chef/my-webui\.pem$} else @knife.admin_client_key.should == '/home/you/.chef/my-webui.pem' end end it "should not ask the user for the location of the existing admin key if -i is not specified" do @knife.ask_user_for_config @out.string.should_not match(Regexp.escape("Please enter the location of the existing admin client's private key: [#{default_admin_key}]")) if windows? @knife.admin_client_key.should_not == default_admin_key_win32 else @knife.admin_client_key.should_not == default_admin_key end end it "asks the user for the location of a chef repo" do @knife.ask_user_for_config @out.string.should match(Regexp.escape("Please enter the path to a chef repository (or leave blank):")) @knife.chef_repo.should == '' end it "asks the users for the name of the validation client" do @knife.ask_user_for_config @out.string.should match(Regexp.escape("Please enter the validation clientname: [chef-validator]")) @knife.validation_client_name.should == 'chef-validator' end it "should not ask the users for the name of the validation client if --validation_client_name is specified" do @knife.config[:validation_client_name] = 'my-validator' @knife.ask_user_for_config @out.string.should_not match(Regexp.escape("Please enter the validation clientname:")) @knife.validation_client_name.should == 'my-validator' end it "asks the users for the location of the validation key" do @knife.ask_user_for_config @out.string.should match(Regexp.escape("Please enter the location of the validation key: [#{default_validator_key}]")) if windows? @knife.validation_key.capitalize.should == default_validator_key_win32.capitalize else @knife.validation_key.should == default_validator_key end end it "should not ask the users for the location of the validation key if --validation_key is specified" do @knife.config[:validation_key] = '/home/you/.chef/my-validation.pem' @knife.ask_user_for_config @out.string.should_not match(Regexp.escape("Please enter the location of the validation key:")) if windows? @knife.validation_key.should match %r{^[A-Za-z]:/home/you/\.chef/my-validation\.pem$} else @knife.validation_key.should == '/home/you/.chef/my-validation.pem' end end it "should not ask the user for anything if -i and all other properties are specified" do @knife.config[:initial] = true @knife.config[:chef_server_url] = 'http://localhost:5000' @knife.config[:node_name] = 'testnode' @knife.config[:admin_client_name] = 'my-webui' @knife.config[:admin_client_key] = '/home/you/.chef/my-webui.pem' @knife.config[:validation_client_name] = 'my-validator' @knife.config[:validation_key] = '/home/you/.chef/my-validation.pem' @knife.config[:repository] = '' @knife.config[:client_key] = '/home/you/a-new-user.pem' Etc.stub!(:getlogin).and_return('a-new-user') @knife.ask_user_for_config @out.string.should match(/\s*/) @knife.new_client_name.should == 'testnode' @knife.chef_server.should == 'http://localhost:5000' @knife.admin_client_name.should == 'my-webui' if windows? @knife.admin_client_key.should match %r{^[A-Za-z]:/home/you/\.chef/my-webui\.pem$} @knife.validation_key.should match %r{^[A-Za-z]:/home/you/\.chef/my-validation\.pem$} @knife.new_client_key.should match %r{^[A-Za-z]:/home/you/a-new-user\.pem$} else @knife.admin_client_key.should == '/home/you/.chef/my-webui.pem' @knife.validation_key.should == '/home/you/.chef/my-validation.pem' @knife.new_client_key.should == '/home/you/a-new-user.pem' end @knife.validation_client_name.should == 'my-validator' @knife.chef_repo.should == '' end it "writes the new data to a config file" do File.stub!(:expand_path).with("/home/you/.chef/knife.rb").and_return("/home/you/.chef/knife.rb") File.stub!(:expand_path).with("/home/you/.chef/#{Etc.getlogin}.pem").and_return("/home/you/.chef/#{Etc.getlogin}.pem") File.stub!(:expand_path).with(default_validator_key).and_return(default_validator_key) File.stub!(:expand_path).with(default_admin_key).and_return(default_admin_key) FileUtils.should_receive(:mkdir_p).with("/home/you/.chef") config_file = StringIO.new ::File.should_receive(:open).with("/home/you/.chef/knife.rb", "w").and_yield config_file @knife.config[:repository] = '/home/you/chef-repo' @knife.run config_file.string.should match(/^node_name[\s]+'#{Etc.getlogin}'$/) config_file.string.should match(%r{^client_key[\s]+'/home/you/.chef/#{Etc.getlogin}.pem'$}) config_file.string.should match(/^validation_client_name\s+'chef-validator'$/) config_file.string.should match(%r{^validation_key\s+'#{default_validator_key}'$}) config_file.string.should match(%r{^chef_server_url\s+'#{default_server_url}'$}) config_file.string.should match(%r{cookbook_path\s+\[ '/home/you/chef-repo/cookbooks' \]}) end it "creates a new client when given the --initial option" do File.should_receive(:expand_path).with("/home/you/.chef/knife.rb").and_return("/home/you/.chef/knife.rb") File.should_receive(:expand_path).with("/home/you/.chef/a-new-user.pem").and_return("/home/you/.chef/a-new-user.pem") File.should_receive(:expand_path).with(default_validator_key).and_return(default_validator_key) File.should_receive(:expand_path).with(default_admin_key).and_return(default_admin_key) Chef::Config[:node_name] = "webmonkey.example.com" user_command = Chef::Knife::UserCreate.new user_command.should_receive(:run) Etc.stub!(:getlogin).and_return("a-new-user") Chef::Knife::UserCreate.stub!(:new).and_return(user_command) FileUtils.should_receive(:mkdir_p).with("/home/you/.chef") ::File.should_receive(:open).with("/home/you/.chef/knife.rb", "w") @knife.config[:initial] = true @knife.config[:user_password] = "blah" @knife.run user_command.name_args.should == Array("a-new-user") user_command.config[:user_password].should == "blah" user_command.config[:admin].should be_true user_command.config[:file].should == "/home/you/.chef/a-new-user.pem" user_command.config[:yes].should be_true user_command.config[:disable_editing].should be_true end end chef-11.8.2/spec/unit/knife/client_reregister_spec.rb0000644000004100000410000000400512254362222022614 0ustar www-datawww-data# # Author:: Thomas Bishop () # Copyright:: Copyright (c) 2011 Thomas Bishop # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::ClientReregister do before(:each) do @knife = Chef::Knife::ClientReregister.new @knife.name_args = [ 'adam' ] @client_mock = mock('client_mock', :private_key => "foo_key") @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) end context "when no client name is given on the command line" do before do @knife.name_args = [] end it 'should print usage and exit when a client name is not provided' do @knife.should_receive(:show_usage) @knife.ui.should_receive(:fatal) lambda { @knife.run }.should raise_error(SystemExit) end end context 'when not configured for file output' do it 'reregisters the client and prints the key' do Chef::ApiClient.should_receive(:reregister).with('adam').and_return(@client_mock) @knife.run @stdout.string.should match( /foo_key/ ) end end context 'when configured for file output' do it 'should write the private key to a file' do Chef::ApiClient.should_receive(:reregister).with('adam').and_return(@client_mock) @knife.config[:file] = '/tmp/monkeypants' filehandle = StringIO.new File.should_receive(:open).with('/tmp/monkeypants', 'w').and_yield(filehandle) @knife.run filehandle.string.should == "foo_key" end end end chef-11.8.2/spec/unit/knife/environment_create_spec.rb0000644000004100000410000000510212254362222022771 0ustar www-datawww-data# # Author:: Stephen Delano () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::EnvironmentCreate do before(:each) do @knife = Chef::Knife::EnvironmentCreate.new @knife.stub!(:msg).and_return true @knife.stub!(:output).and_return true @knife.stub!(:show_usage).and_return true @knife.name_args = [ "production" ] @environment = Chef::Environment.new @environment.stub!(:save) Chef::Environment.stub!(:new).and_return @environment @knife.stub!(:edit_data).and_return @environment end describe "run" do it "should create a new environment" do Chef::Environment.should_receive(:new) @knife.run end it "should set the environment name" do @environment.should_receive(:name).with("production") @knife.run end it "should not print the environment" do @knife.should_not_receive(:output) @knife.run end it "should prompt you to edit the data" do @knife.should_receive(:edit_data).with(@environment) @knife.run end it "should save the environment" do @environment.should_receive(:save) @knife.run end it "should show usage and exit when no environment name is provided" do @knife.name_args = [ ] @knife.ui.should_receive(:fatal) @knife.should_receive(:show_usage) lambda { @knife.run }.should raise_error(SystemExit) end describe "with --description" do before(:each) do @knife.config[:description] = "This is production" end it "should set the description" do @environment.should_receive(:description).with("This is production") @knife.run end end describe "with --print-after" do before(:each) do @knife.config[:print_after] = true end it "should pretty print the environment, formatted for display" do @knife.should_receive(:output).with(@environment) @knife.run end end end end chef-11.8.2/spec/unit/knife/cookbook_site_download_spec.rb0000644000004100000410000001335512254362222023634 0ustar www-datawww-data# # Author:: Thomas Bishop () # Copyright:: Copyright (c) 2012 Thomas Bishop # License:: Apache License, Version 2.0 # # 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. # require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') describe Chef::Knife::CookbookSiteDownload do describe 'run' do before do @knife = Chef::Knife::CookbookSiteDownload.new @knife.name_args = ['apache2'] @noauth_rest = mock 'no auth rest' @stdout = StringIO.new @cookbook_api_url = 'http://cookbooks.opscode.com/api/v1/cookbooks' @version = '1.0.2' @version_us = @version.gsub '.', '_' @current_data = { 'deprecated' => false, 'latest_version' => "#{@cookbook_api_url}/apache2/versions/#{@version_us}", 'replacement' => 'other_apache2' } @knife.ui.stub(:stdout).and_return(@stdout) @knife.stub(:noauth_rest).and_return(@noauth_rest) @noauth_rest.should_receive(:get_rest). with("#{@cookbook_api_url}/apache2"). and_return(@current_data) end context 'when the cookbook is deprecated and not forced' do before do @current_data['deprecated'] = true end it 'should warn with info about the replacement' do @knife.ui.should_receive(:warn). with(/.+deprecated.+replaced by other_apache2.+/i) @knife.ui.should_receive(:warn). with(/use --force.+download.+/i) @knife.run end end context 'when' do before do @cookbook_data = { 'version' => @version, 'file' => "http://example.com/apache2_#{@version_us}.tgz" } @temp_file = stub :path => "/tmp/apache2_#{@version_us}.tgz" @file = File.join(Dir.pwd, "apache2-#{@version}.tar.gz") @noauth_rest.should_receive(:sign_on_redirect=).with(false) end context 'downloading the latest version' do before do @noauth_rest.should_receive(:get_rest). with(@current_data['latest_version']). and_return(@cookbook_data) @noauth_rest.should_receive(:get_rest). with(@cookbook_data['file'], true). and_return(@temp_file) end context 'and it is deprecated and with --force' do before do @current_data['deprecated'] = true @knife.config[:force] = true end it 'should download the latest version' do @knife.ui.should_receive(:warn). with(/.+deprecated.+replaced by other_apache2.+/i) FileUtils.should_receive(:cp).with(@temp_file.path, @file) @knife.run @stdout.string.should match /downloading apache2.+version.+#{Regexp.escape(@version)}/i @stdout.string.should match /cookbook save.+#{Regexp.escape(@file)}/i end end it 'should download the latest version' do FileUtils.should_receive(:cp).with(@temp_file.path, @file) @knife.run @stdout.string.should match /downloading apache2.+version.+#{Regexp.escape(@version)}/i @stdout.string.should match /cookbook save.+#{Regexp.escape(@file)}/i end context 'with -f or --file' do before do @file = '/opt/chef/cookbooks/apache2.tar.gz' @knife.config[:file] = @file FileUtils.should_receive(:cp).with(@temp_file.path, @file) end it 'should download the cookbook to the desired file' do @knife.run @stdout.string.should match /downloading apache2.+version.+#{Regexp.escape(@version)}/i @stdout.string.should match /cookbook save.+#{Regexp.escape(@file)}/i end end it 'should provide an accessor to the version' do FileUtils.stub(:cp).and_return(true) @knife.version.should == @version @knife.run end end context 'downloading a cookbook of a specific version' do before do @version = '1.0.1' @version_us = @version.gsub '.', '_' @cookbook_data = { 'version' => @version, 'file' => "http://example.com/apache2_#{@version_us}.tgz" } @temp_file = stub :path => "/tmp/apache2_#{@version_us}.tgz" @file = File.join(Dir.pwd, "apache2-#{@version}.tar.gz") @knife.name_args << @version end it 'should download the desired version' do @noauth_rest.should_receive(:get_rest). with("#{@cookbook_api_url}/apache2/versions/#{@version_us}"). and_return(@cookbook_data) @noauth_rest.should_receive(:get_rest). with(@cookbook_data['file'], true). and_return(@temp_file) FileUtils.should_receive(:cp).with(@temp_file.path, @file) @knife.run @stdout.string.should match /downloading apache2.+version.+#{Regexp.escape(@version)}/i @stdout.string.should match /cookbook save.+#{Regexp.escape(@file)}/i end end end end end chef-11.8.2/spec/unit/knife/cookbook_test_spec.rb0000644000004100000410000000575512254362222021765 0ustar www-datawww-data# # Author:: Stephen Delano ()$ # Author:: Matthew Kent () # Copyright:: Copyright (c) 2010 Opscode, Inc.$ # Copyright:: Copyright (c) 2010 Matthew Kent # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' Chef::Knife::CookbookTest.load_deps describe Chef::Knife::CookbookTest do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::CookbookTest.new @knife.config[:cookbook_path] = File.join(CHEF_SPEC_DATA,'cookbooks') @knife.cookbook_loader.stub!(:cookbook_exists?).and_return(true) @cookbooks = [] %w{tats central_market jimmy_johns pho}.each do |cookbook_name| @cookbooks << Chef::CookbookVersion.new(cookbook_name) end @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) end describe "run" do it "should test the cookbook" do @knife.stub!(:test_cookbook).and_return(true) @knife.name_args = ["italian"] @knife.should_receive(:test_cookbook).with("italian") @knife.run end it "should test multiple cookbooks when provided" do @knife.stub!(:test_cookbook).and_return(true) @knife.name_args = ["tats", "jimmy_johns"] @knife.should_receive(:test_cookbook).with("tats") @knife.should_receive(:test_cookbook).with("jimmy_johns") @knife.should_not_receive(:test_cookbook).with("central_market") @knife.should_not_receive(:test_cookbook).with("pho") @knife.run end it "should test both ruby and templates" do @knife.name_args = ["example"] @knife.config[:cookbook_path].should_not be_empty Array(@knife.config[:cookbook_path]).reverse.each do |path| @knife.should_receive(:test_ruby).with(an_instance_of(Chef::Cookbook::SyntaxCheck)) @knife.should_receive(:test_templates).with(an_instance_of(Chef::Cookbook::SyntaxCheck)) end @knife.run end describe "with -a or --all" do it "should test all of the cookbooks" do @knife.stub!(:test_cookbook).and_return(true) @knife.config[:all] = true @loader = {} @loader.stub!(:load_cookbooks).and_return(@loader) @cookbooks.each do |cookbook| @loader[cookbook.name] = cookbook end @knife.stub!(:cookbook_loader).and_return(@loader) @loader.each do |key, cookbook| @knife.should_receive(:test_cookbook).with(cookbook.name) end @knife.run end end end end chef-11.8.2/spec/unit/knife/cookbook_site_install_spec.rb0000644000004100000410000001435212254362222023471 0ustar www-datawww-data# # Author:: Steven Danna () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper")) describe Chef::Knife::CookbookSiteInstall do before(:each) do require 'chef/knife/core/cookbook_scm_repo' @knife = Chef::Knife::CookbookSiteInstall.new @knife.config = {} if Chef::Platform.windows? @install_path = 'C:/tmp/chef' else @install_path = '/var/tmp/chef' end @knife.config[:cookbook_path] = [ @install_path ] @stdout = StringIO.new @stderr = StringIO.new @knife.stub!(:stderr).and_return(@stdout) @knife.stub!(:stdout).and_return(@stdout) #Assume all external commands would have succeed. :( File.stub!(:unlink) File.stub!(:rmtree) @knife.stub!(:shell_out!).and_return(true) #CookbookSiteDownload Stup @downloader = {} @knife.stub!(:download_cookbook_to).and_return(@downloader) @downloader.stub!(:version).and_return do if @knife.name_args.size == 2 @knife.name_args[1] else "0.3.0" end end #Stubs for CookbookSCMRepo @repo = stub(:sanity_check => true, :reset_to_default_state => true, :prepare_to_import => true, :finalize_updates_to => true, :merge_updates_from => true) Chef::Knife::CookbookSCMRepo.stub!(:new).and_return(@repo) end describe "run" do it "should return an error if a cookbook name is not provided" do @knife.name_args = [] @knife.ui.should_receive(:error).with("Please specify a cookbook to download and install.") lambda { @knife.run }.should raise_error(SystemExit) end it "should return an error if more than two arguments are given" do @knife.name_args = ["foo", "bar", "baz"] @knife.ui.should_receive(:error).with("Installing multiple cookbooks at once is not supported.") lambda { @knife.run }.should raise_error(SystemExit) end it "should return an error if the second argument is not a version" do @knife.name_args = ["getting-started", "1pass"] @knife.ui.should_receive(:error).with("Installing multiple cookbooks at once is not supported.") lambda { @knife.run }.should raise_error(SystemExit) end it "should return an error if the second argument is a four-digit version" do @knife.name_args = ["getting-started", "0.0.0.1"] @knife.ui.should_receive(:error).with("Installing multiple cookbooks at once is not supported.") lambda { @knife.run }.should raise_error(SystemExit) end it "should return an error if the second argument is a one-digit version" do @knife.name_args = ["getting-started", "1"] @knife.ui.should_receive(:error).with("Installing multiple cookbooks at once is not supported.") lambda { @knife.run }.should raise_error(SystemExit) end it "should install the specified version if second argument is a three-digit version" do @knife.name_args = ["getting-started", "0.1.0"] @knife.config[:no_deps] = true upstream_file = File.join(@install_path, "getting-started.tar.gz") @knife.should_receive(:download_cookbook_to).with(upstream_file) @knife.should_receive(:extract_cookbook).with(upstream_file, "0.1.0") @knife.should_receive(:clear_existing_files).with(File.join(@install_path, "getting-started")) @repo.should_receive(:merge_updates_from).with("getting-started", "0.1.0") @knife.run end it "should install the specified version if second argument is a two-digit version" do @knife.name_args = ["getting-started", "0.1"] @knife.config[:no_deps] = true upstream_file = File.join(@install_path, "getting-started.tar.gz") @knife.should_receive(:download_cookbook_to).with(upstream_file) @knife.should_receive(:extract_cookbook).with(upstream_file, "0.1") @knife.should_receive(:clear_existing_files).with(File.join(@install_path, "getting-started")) @repo.should_receive(:merge_updates_from).with("getting-started", "0.1") @knife.run end it "should install the latest version if only a cookbook name is given" do @knife.name_args = ["getting-started"] @knife.config[:no_deps] = true upstream_file = File.join(@install_path, "getting-started.tar.gz") @knife.should_receive(:download_cookbook_to).with(upstream_file) @knife.should_receive(:extract_cookbook).with(upstream_file, "0.3.0") @knife.should_receive(:clear_existing_files).with(File.join(@install_path, "getting-started")) @repo.should_receive(:merge_updates_from).with("getting-started", "0.3.0") @knife.run end it "should not create/reset git branches if use_current_branch is set" do @knife.name_args = ["getting-started"] @knife.config[:use_current_branch] = true @knife.config[:no_deps] = true upstream_file = File.join(@install_path, "getting-started.tar.gz") @repo.should_not_receive(:prepare_to_import) @repo.should_not_receive(:reset_to_default_state) @knife.run end it "should not raise an error if cookbook_path is a string" do @knife.config[:cookbook_path] = @install_path @knife.config[:no_deps] = true @knife.name_args = ["getting-started"] upstream_file = File.join(@install_path, "getting-started.tar.gz") @knife.should_receive(:download_cookbook_to).with(upstream_file) @knife.should_receive(:extract_cookbook).with(upstream_file, "0.3.0") @knife.should_receive(:clear_existing_files).with(File.join(@install_path, "getting-started")) @repo.should_receive(:merge_updates_from).with("getting-started", "0.3.0") lambda { @knife.run }.should_not raise_error end end end chef-11.8.2/spec/unit/knife/environment_edit_spec.rb0000644000004100000410000000464312254362222022464 0ustar www-datawww-data# # Author:: Stephen Delano () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::EnvironmentEdit do before(:each) do @knife = Chef::Knife::EnvironmentEdit.new @knife.ui.stub!(:msg).and_return true @knife.ui.stub!(:output).and_return true @knife.ui.stub!(:show_usage).and_return true @knife.name_args = [ "production" ] @environment = Chef::Environment.new @environment.name("production") @environment.description("Please edit me") @environment.stub!(:save).and_return true Chef::Environment.stub!(:load).and_return @environment @knife.ui.stub(:edit_data).and_return @environment end it "should load the environment" do Chef::Environment.should_receive(:load).with("production") @knife.run end it "should let you edit the environment" do @knife.ui.should_receive(:edit_data).with(@environment) @knife.run end it "should save the edited environment data" do pansy = Chef::Environment.new @environment.name("new_environment_name") @knife.ui.should_receive(:edit_data).with(@environment).and_return(pansy) pansy.should_receive(:save) @knife.run end it "should not save the unedited environment data" do @environment.should_not_receive(:save) @knife.run end it "should not print the environment" do @knife.should_not_receive(:output) @knife.run end it "shoud show usage and exit when no environment name is provided" do @knife.name_args = [] @knife.should_receive(:show_usage) lambda { @knife.run }.should raise_error(SystemExit) end describe "with --print-after" do it "should pretty print the environment, formatted for display" do @knife.config[:print_after] = true @knife.ui.should_receive(:output).with(@environment) @knife.run end end end chef-11.8.2/spec/unit/knife/cookbook_bulk_delete_spec.rb0000644000004100000410000000626612254362222023263 0ustar www-datawww-data# # Author:: Stephen Delano () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::CookbookBulkDelete do before(:each) do Chef::Log.logger = Logger.new(StringIO.new) Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::CookbookBulkDelete.new @knife.config = {:print_after => nil} @knife.name_args = ["."] @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) @knife.ui.stub!(:confirm).and_return(true) @cookbooks = Hash.new %w{cheezburger pizza lasagna}.each do |cookbook_name| cookbook = Chef::CookbookVersion.new(cookbook_name) @cookbooks[cookbook_name] = cookbook end @rest = mock("Chef::REST") @rest.stub!(:get_rest).and_return(@cookbooks) @rest.stub!(:delete_rest).and_return(true) @knife.stub!(:rest).and_return(@rest) Chef::CookbookVersion.stub!(:list).and_return(@cookbooks) end describe "when there are several cookbooks on the server" do before do @cheezburger = {'cheezburger' => {"url" => "file:///dev/null", "versions" => [{"url" => "file:///dev/null-cheez", "version" => "1.0.0"}]}} @rest.stub!(:get_rest).with('cookbooks/cheezburger').and_return(@cheezburger) @pizza = {'pizza' => {"url" => "file:///dev/null", "versions" => [{"url" => "file:///dev/null-pizza", "version" => "2.0.0"}]}} @rest.stub!(:get_rest).with('cookbooks/pizza').and_return(@pizza) @lasagna = {'lasagna' => {"url" => "file:///dev/null", "versions" => [{"url" => "file:///dev/null-lasagna", "version" => "3.0.0"}]}} @rest.stub!(:get_rest).with('cookbooks/lasagna').and_return(@lasagna) end it "should print the cookbooks you are about to delete" do expected = @knife.ui.list(@cookbooks.keys.sort, :columns_down) @knife.run @stdout.string.should match(/#{expected}/) end it "should confirm you really want to delete them" do @knife.ui.should_receive(:confirm) @knife.run end it "should delete each cookbook" do {"cheezburger" => "1.0.0", "pizza" => "2.0.0", "lasagna" => '3.0.0'}.each do |cookbook_name, version| @rest.should_receive(:delete_rest).with("cookbooks/#{cookbook_name}/#{version}") end @knife.run end it "should only delete cookbooks that match the regex" do @knife.name_args = ["cheezburger"] @rest.should_receive(:delete_rest).with('cookbooks/cheezburger/1.0.0') @knife.run end end it "should exit if the regex is not provided" do @knife.name_args = [] lambda { @knife.run }.should raise_error(SystemExit) end end chef-11.8.2/spec/unit/knife/knife_help.rb0000644000004100000410000000555412254362222020207 0ustar www-datawww-data# # Author:: Bryan McLellan # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::Help do before(:each) do # Perilously use the build in list even though it is dynamic so we don't get warnings about the constant # HELP_TOPICS = [ "foo", "bar", "knife-kittens", "ceiling-cat", "shell" ] @knife = Chef::Knife::Help.new end it "should return a list of help topics" do @knife.help_topics.should include("knife-status") end it "should run man for you" do @knife.name_args = [ "shell" ] @knife.should_receive(:exec).with(/^man \/.*\/shell.1$/) @knife.run end it "should suggest topics" do @knife.name_args = [ "list" ] @knife.ui.stub!(:msg) @knife.ui.should_receive(:info).with("Available help topics are: ") @knife.ui.should_receive(:msg).with(/knife/) @knife.stub!(:exec) @knife.should_receive(:exit).with(1) @knife.run end describe "find_manpage_path" do it "should find the man page in the gem" do @knife.find_manpage_path("shell").should =~ /distro\/common\/man\/man1\/chef-shell.1$/ end it "should provide the man page name if not in the gem" do @knife.find_manpage_path("foo").should == "foo" end end describe "find_manpages_for_query" do it "should error if it does not find a match" do @knife.ui.stub!(:error) @knife.ui.stub!(:info) @knife.ui.stub!(:msg) @knife.should_receive(:exit).with(1) @knife.ui.should_receive(:error).with("No help found for 'chickens'") @knife.ui.should_receive(:msg).with(/knife/) @knife.find_manpages_for_query("chickens") end end describe "print_help_topics" do it "should print the known help topics" do @knife.ui.stub!(:msg) @knife.ui.stub!(:info) @knife.ui.should_receive(:msg).with(/knife/) @knife.print_help_topics end it "should shorten topics prefixed by knife-" do @knife.ui.stub!(:msg) @knife.ui.stub!(:info) @knife.ui.should_receive(:msg).with(/node/) @knife.print_help_topics end it "should not leave topics prefixed by knife-" do @knife.ui.stub!(:msg) @knife.ui.stub!(:info) @knife.ui.should_not_receive(:msg).with(/knife-node/) @knife.print_help_topics end end end chef-11.8.2/spec/unit/knife/user_create_spec.rb0000644000004100000410000000536312254362222021414 0ustar www-datawww-data# # Author:: Steven Danna () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' Chef::Knife::UserCreate.load_deps describe Chef::Knife::UserCreate do before(:each) do @knife = Chef::Knife::UserCreate.new @knife.name_args = [ 'a_user' ] @knife.config[:user_password] = "foobar" @user = Chef::User.new @user.name "a_user" @user_with_private_key = Chef::User.new @user_with_private_key.name "a_user" @user_with_private_key.private_key 'private_key' @user.stub!(:create).and_return(@user_with_private_key) Chef::User.stub!(:new).and_return(@user) Chef::User.stub!(:from_hash).and_return(@user) @knife.stub!(:edit_data).and_return(@user.to_hash) @stdout = StringIO.new @stderr = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) @knife.ui.stub!(:stderr).and_return(@stderr) end it "creates a new user" do Chef::User.should_receive(:new).and_return(@user) @user.should_receive(:create) @knife.run @stdout.string.should match /created user.+a_user/i end it "sets the password" do @knife.config[:user_password] = "a_password" @user.should_receive(:password).with("a_password") @knife.run end it "exits with an error if password is blank" do @knife.config[:user_password] = '' lambda { @knife.run }.should raise_error SystemExit @stderr.string.should match /You must specify a non-blank password/ end it "sets the user name" do @user.should_receive(:name).with("a_user") @knife.run end it "sets the public key if given" do @knife.config[:user_key] = "/a/filename" File.stub(:read).with(File.expand_path("/a/filename")).and_return("a_key") @user.should_receive(:public_key).with("a_key") @knife.run end it "allows you to edit the data" do @knife.should_receive(:edit_data).with(@user) @knife.run end it "writes the private key to a file when --file is specified" do @knife.config[:file] = "/tmp/a_file" filehandle = mock("filehandle") filehandle.should_receive(:print).with('private_key') File.should_receive(:open).with("/tmp/a_file", "w").and_yield(filehandle) @knife.run end end chef-11.8.2/spec/unit/knife/node_edit_spec.rb0000644000004100000410000000674312254362222021050 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' Chef::Knife::NodeEdit.load_deps describe Chef::Knife::NodeEdit do # helper to convert the view from Chef objects into Ruby objects representing JSON def deserialized_json_view actual = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json_pretty(@knife.node_editor.send(:view))) end before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::NodeEdit.new @knife.config = { :editor => 'cat', :attribute => nil, :print_after => nil } @knife.name_args = [ "adam" ] @node = Chef::Node.new() end it "should load the node" do Chef::Node.should_receive(:load).with("adam").and_return(@node) @knife.node end describe "after loading the node" do before do @knife.stub!(:node).and_return(@node) @node.automatic_attrs = {:go => :away} @node.default_attrs = {:hide => :me} @node.override_attrs = {:dont => :show} @node.normal_attrs = {:do_show => :these} @node.chef_environment("prod") @node.run_list("recipe[foo]") end it "creates a view of the node without attributes from roles or ohai" do actual = deserialized_json_view actual.should_not have_key("automatic") actual.should_not have_key("override") actual.should_not have_key("default") actual["normal"].should == {"do_show" => "these"} actual["run_list"].should == ["recipe[foo]"] actual["chef_environment"].should == "prod" end it "shows the extra attributes when given the --all option" do @knife.config[:all_attributes] = true actual = deserialized_json_view actual["automatic"].should == {"go" => "away"} actual["override"].should == {"dont" => "show"} actual["default"].should == {"hide" => "me"} actual["normal"].should == {"do_show" => "these"} actual["run_list"].should == ["recipe[foo]"] actual["chef_environment"].should == "prod" end it "does not consider unedited data updated" do view = deserialized_json_view @knife.node_editor.send(:apply_updates, view) @knife.node_editor.should_not be_updated end it "considers edited data updated" do view = deserialized_json_view view["run_list"] << "role[fuuu]" @knife.node_editor.send(:apply_updates, view) @knife.node_editor.should be_updated end end describe "edit_node" do before do @knife.stub!(:node).and_return(@node) end let(:subject) { @knife.node_editor.edit_node } it "raises an exception when editing is disabled" do @knife.config[:disable_editing] = true expect{ subject }.to raise_error(SystemExit) end it "raises an exception when the editor is not set" do @knife.config[:editor] = nil expect{ subject }.to raise_error(SystemExit) end end end chef-11.8.2/spec/unit/knife/role_create_spec.rb0000644000004100000410000000433612254362222021376 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::RoleCreate do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::RoleCreate.new @knife.config = { :description => nil } @knife.name_args = [ "adam" ] @knife.stub!(:output).and_return(true) @role = Chef::Role.new() @role.stub!(:save) Chef::Role.stub!(:new).and_return(@role) @knife.stub!(:edit_data).and_return(@role) @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) end describe "run" do it "should create a new role" do Chef::Role.should_receive(:new).and_return(@role) @knife.run end it "should set the role name" do @role.should_receive(:name).with("adam") @knife.run end it "should not print the role" do @knife.should_not_receive(:output) @knife.run end it "should allow you to edit the data" do @knife.should_receive(:edit_data).with(@role) @knife.run end it "should save the role" do @role.should_receive(:save) @knife.run end describe "with -d or --description" do it "should set the description" do @knife.config[:description] = "All is bob" @role.should_receive(:description).with("All is bob") @knife.run end end describe "with -p or --print-after" do it "should pretty print the node, formatted for display" do @knife.config[:print_after] = true @knife.should_receive(:output).with(@role) @knife.run end end end end chef-11.8.2/spec/unit/knife/tag_list_spec.rb0000644000004100000410000000111512254362222020710 0ustar www-datawww-datarequire 'spec_helper' describe Chef::Knife::TagList do before(:each) do Chef::Config[:node_name] = "webmonkey.example.com" @knife = Chef::Knife::TagList.new @knife.name_args = [ Chef::Config[:node_name], "sadtag" ] @node = Chef::Node.new @node.stub! :save @node.tags << "sadtag" << "happytag" Chef::Node.stub!(:load).and_return @node end describe "run" do it "can list tags on a node" do expected = %w(sadtag happytag) @node.tags.should == expected @knife.should_receive(:output).with(expected) @knife.run end end end chef-11.8.2/spec/unit/knife/user_delete_spec.rb0000644000004100000410000000232612254362222021407 0ustar www-datawww-data# # Author:: Steven Danna () # Copyright:: Copyright (c) 2012 Opscode, Inc # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::UserDelete do before(:each) do Chef::Knife::UserDelete.load_deps @knife = Chef::Knife::UserDelete.new @knife.name_args = [ 'my_user' ] end it 'deletes the user' do @knife.should_receive(:delete_object).with(Chef::User, 'my_user') @knife.run end it 'prints usage and exits when a user name is not provided' do @knife.name_args = [] @knife.should_receive(:show_usage) @knife.ui.should_receive(:fatal) lambda { @knife.run }.should raise_error(SystemExit) end end chef-11.8.2/spec/unit/knife/cookbook_list_spec.rb0000644000004100000410000000605512254362222021753 0ustar www-datawww-data# # Author:: Thomas Bishop () # Copyright:: Copyright (c) 2011 Thomas Bishop # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::CookbookList do before do @knife = Chef::Knife::CookbookList.new @rest_mock = mock('rest') @knife.stub!(:rest).and_return(@rest_mock) @cookbook_names = ['apache2', 'mysql'] @base_url = 'https://server.example.com/cookbooks' @cookbook_data = {} @cookbook_names.each do |item| @cookbook_data[item] = {'url' => "#{@base_url}/#{item}", 'versions' => [{'version' => '1.0.1', 'url' => "#{@base_url}/#{item}/1.0.1"}]} end @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) end describe 'run' do it 'should display the latest version of the cookbooks' do @rest_mock.should_receive(:get_rest).with('/cookbooks?num_versions=1'). and_return(@cookbook_data) @knife.run @cookbook_names.each do |item| @stdout.string.should match /#{item}\s+1\.0\.1/ end end it 'should query cookbooks for the configured environment' do @knife.config[:environment] = 'production' @rest_mock.should_receive(:get_rest). with('/environments/production/cookbooks?num_versions=1'). and_return(@cookbook_data) @knife.run end describe 'with -w or --with-uri' do it 'should display the cookbook uris' do @knife.config[:with_uri] = true @rest_mock.stub(:get_rest).and_return(@cookbook_data) @knife.run @cookbook_names.each do |item| pattern = /#{Regexp.escape(@cookbook_data[item]['versions'].first['url'])}/ @stdout.string.should match pattern end end end describe 'with -a or --all' do before do @cookbook_names.each do |item| @cookbook_data[item]['versions'] << {'version' => '1.0.0', 'url' => "#{@base_url}/#{item}/1.0.0"} end end it 'should display all versions of the cookbooks' do @knife.config[:all_versions] = true @rest_mock.should_receive(:get_rest).with('/cookbooks?num_versions=all'). and_return(@cookbook_data) @knife.run @cookbook_names.each do |item| @stdout.string.should match /#{item}\s+1\.0\.1\s+1\.0\.0/ end end end end end chef-11.8.2/spec/unit/knife/user_list_spec.rb0000644000004100000410000000167712254362222021130 0ustar www-datawww-data# # Author:: Steven Danna # Copyright:: Copyright (c) 2012 Opscode, Inc # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::UserList do before(:each) do Chef::Knife::UserList.load_deps @knife = Chef::Knife::UserList.new end it 'lists the users' do Chef::User.should_receive(:list) @knife.should_receive(:format_list_for_display) @knife.run end end chef-11.8.2/spec/unit/knife/config_file_selection_spec.rb0000644000004100000410000001010112254362222023406 0ustar www-datawww-data# # Author:: Nicolas Vinot () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') require 'tmpdir' describe Chef::Knife do let(:missing_config_fetcher) do double(Chef::ConfigFetcher, :config_missing? => true) end let(:available_config_fetcher) do double(Chef::ConfigFetcher, :config_missing? => false, :read_config => "") end def have_config_file(path) Chef::ConfigFetcher.should_receive(:new).at_least(1).times.with(path, nil).and_return(available_config_fetcher) end before do # Make sure tests can run when HOME is not set... @original_home = ENV["HOME"] ENV["HOME"] = Dir.tmpdir end after do ENV["HOME"] = @original_home end before :each do Chef::Config.stub!(:from_file).and_return(true) Chef::ConfigFetcher.stub(:new).and_return(missing_config_fetcher) end it "configure knife from KNIFE_HOME env variable" do env_config = File.expand_path(File.join(Dir.tmpdir, 'knife.rb')) have_config_file(env_config) ENV['KNIFE_HOME'] = Dir.tmpdir @knife = Chef::Knife.new @knife.configure_chef @knife.config[:config_file].should == env_config end it "configure knife from PWD" do pwd_config = "#{Dir.pwd}/knife.rb" have_config_file(pwd_config) @knife = Chef::Knife.new @knife.configure_chef @knife.config[:config_file].should == pwd_config end it "configure knife from UPWARD" do upward_dir = File.expand_path "#{Dir.pwd}/.chef" upward_config = File.expand_path "#{upward_dir}/knife.rb" have_config_file(upward_config) Chef::Knife.stub!(:chef_config_dir).and_return(upward_dir) @knife = Chef::Knife.new @knife.configure_chef @knife.config[:config_file].should == upward_config end it "configure knife from HOME" do home_config = File.expand_path(File.join("#{ENV['HOME']}", "/.chef/knife.rb")) have_config_file(home_config) @knife = Chef::Knife.new @knife.configure_chef @knife.config[:config_file].should == home_config end it "configure knife from nothing" do ::File.stub!(:exist?).and_return(false) @knife = Chef::Knife.new @knife.ui.should_receive(:warn).with("No knife configuration file found") @knife.configure_chef @knife.config[:config_file].should be_nil end it "configure knife precedence" do env_config = File.join(Dir.tmpdir, 'knife.rb') pwd_config = "#{Dir.pwd}/knife.rb" upward_dir = File.expand_path "#{Dir.pwd}/.chef" upward_config = File.expand_path "#{upward_dir}/knife.rb" home_config = File.expand_path(File.join("#{ENV['HOME']}", "/.chef/knife.rb")) configs = [ env_config, pwd_config, upward_config, home_config ] Chef::Knife.stub!(:chef_config_dir).and_return(upward_dir) ENV['KNIFE_HOME'] = Dir.tmpdir @knife = Chef::Knife.new @knife.configure_chef @knife.config[:config_file].should be_nil have_config_file(home_config) @knife = Chef::Knife.new @knife.configure_chef @knife.config[:config_file].should == home_config have_config_file(upward_config) @knife = Chef::Knife.new @knife.configure_chef @knife.config[:config_file].should == upward_config have_config_file(pwd_config) @knife = Chef::Knife.new @knife.configure_chef @knife.config[:config_file].should == pwd_config have_config_file(env_config) @knife = Chef::Knife.new @knife.configure_chef @knife.config[:config_file].should == env_config end end chef-11.8.2/spec/unit/knife/status_spec.rb0000644000004100000410000000263112254362222020431 0ustar www-datawww-data# # Author:: Sahil Muthoo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'highline' describe Chef::Knife::Status do before(:each) do node = Chef::Node.new.tap do |n| n.automatic_attrs["fqdn"] = "foobar" n.automatic_attrs["ohai_time"] = 1343845969 end query = mock("Chef::Search::Query") query.stub!(:search).and_yield(node) Chef::Search::Query.stub!(:new).and_return(query) @knife = Chef::Knife::Status.new @stdout = StringIO.new @knife.stub!(:highline).and_return(HighLine.new(StringIO.new, @stdout)) end describe "run" do it "should not colorize output unless it's writing to a tty" do @knife.run @stdout.string.match(/foobar/).should_not be_nil @stdout.string.match(/\e.*ago/).should be_nil end end end chef-11.8.2/spec/unit/knife/client_edit_spec.rb0000644000004100000410000000236012254362222021370 0ustar www-datawww-data# # Author:: Thomas Bishop () # Copyright:: Copyright (c) 2011 Thomas Bishop # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::ClientEdit do before(:each) do @knife = Chef::Knife::ClientEdit.new @knife.name_args = [ 'adam' ] end describe 'run' do it 'should edit the client' do @knife.should_receive(:edit_object).with(Chef::ApiClient, 'adam') @knife.run end it 'should print usage and exit when a client name is not provided' do @knife.name_args = [] @knife.should_receive(:show_usage) @knife.ui.should_receive(:fatal) lambda { @knife.run }.should raise_error(SystemExit) end end end chef-11.8.2/spec/unit/knife/configure_client_spec.rb0000644000004100000410000000565512254362222022436 0ustar www-datawww-data# # Author:: Thomas Bishop () # Copyright:: Copyright (c) 2011 Thomas Bishop # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Knife::ConfigureClient do before do @knife = Chef::Knife::ConfigureClient.new Chef::Config[:chef_server_url] = 'https://chef.example.com' Chef::Config[:validation_client_name] = 'chef-validator' Chef::Config[:validation_key] = '/etc/chef/validation.pem' @stdout = StringIO.new @knife.ui.stub!(:stdout).and_return(@stdout) end describe 'run' do it 'should print usage and exit when a directory is not provided' do @knife.should_receive(:show_usage) @knife.ui.should_receive(:fatal).with(/must provide the directory/) lambda { @knife.run }.should raise_error SystemExit end describe 'when specifing a directory' do before do @knife.name_args = ['/home/bob/.chef'] @client_file = StringIO.new @validation_file = StringIO.new File.should_receive(:open).with('/home/bob/.chef/client.rb', 'w'). and_yield(@client_file) File.should_receive(:open).with('/home/bob/.chef/validation.pem', 'w'). and_yield(@validation_file) IO.should_receive(:read).and_return('foo_bar_baz') end it 'should recursively create the directory' do FileUtils.should_receive(:mkdir_p).with('/home/bob/.chef') @knife.run end it 'should write out the config file' do FileUtils.stub!(:mkdir_p) @knife.run @client_file.string.should match /log_level\s+\:info/ @client_file.string.should match /log_location\s+STDOUT/ @client_file.string.should match /chef_server_url\s+'https\:\/\/chef\.example\.com'/ @client_file.string.should match /validation_client_name\s+'chef-validator'/ end it 'should write out the validation.pem file' do FileUtils.stub!(:mkdir_p) @knife.run @validation_file.string.should match /foo_bar_baz/ end it 'should print information on what is being configured' do FileUtils.stub!(:mkdir_p) @knife.run @stdout.string.should match /creating client configuration/i @stdout.string.should match /writing client\.rb/i @stdout.string.should match /writing validation\.pem/i end end end end chef-11.8.2/spec/unit/log_spec.rb0000644000004100000410000000137612254362222016600 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'tempfile' require 'logger' require 'spec_helper' describe Chef::Log do end chef-11.8.2/spec/unit/client_spec.rb0000644000004100000410000003571312254362222017277 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tim Hinderliter () # Author:: Christopher Walters () # Copyright:: Copyright 2008-2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/run_context' require 'chef/rest' require 'rbconfig' shared_examples_for Chef::Client do before do Chef::Log.logger = Logger.new(StringIO.new) # Node/Ohai data @hostname = "hostname" @fqdn = "hostname.example.org" Chef::Config[:node_name] = @fqdn ohai_data = { :fqdn => @fqdn, :hostname => @hostname, :platform => 'example-platform', :platform_version => 'example-platform-1.0', :data => {} } ohai_data.stub!(:all_plugins).and_return(true) ohai_data.stub!(:data).and_return(ohai_data) Ohai::System.stub!(:new).and_return(ohai_data) @node = Chef::Node.new @node.name(@fqdn) @node.chef_environment("_default") @client = Chef::Client.new @client.node = @node end describe "authentication protocol selection" do after do Chef::Config[:authentication_protocol_version] = "1.0" end context "when the node name is <= 90 bytes" do it "does not force the authentication protocol to 1.1" do Chef::Config[:node_name] = ("f" * 90) # ugly that this happens as a side effect of a getter :( @client.node_name Chef::Config[:authentication_protocol_version].should == "1.0" end end context "when the node name is > 90 bytes" do it "sets the authentication protocol to version 1.1" do Chef::Config[:node_name] = ("f" * 91) # ugly that this happens as a side effect of a getter :( @client.node_name Chef::Config[:authentication_protocol_version].should == "1.1" end end end describe "configuring output formatters" do context "when no formatter has been configured" do before do @client = Chef::Client.new end context "and STDOUT is a TTY" do before do STDOUT.stub!(:tty?).and_return(true) end it "configures the :doc formatter" do @client.formatters_for_run.should == [[:doc]] end context "and force_logger is set" do before do Chef::Config[:force_logger] = true end it "configures the :null formatter" do Chef::Config[:force_logger].should be_true @client.formatters_for_run.should == [[:null]] end end end context "and STDOUT is not a TTY" do before do STDOUT.stub!(:tty?).and_return(false) end it "configures the :null formatter" do @client.formatters_for_run.should == [[:null]] end context "and force_formatter is set" do before do Chef::Config[:force_formatter] = true end it "it configures the :doc formatter" do @client.formatters_for_run.should == [[:doc]] end end end end context "when a formatter is configured" do context "with no output path" do before do @client = Chef::Client.new Chef::Config.add_formatter(:min) end it "does not configure a default formatter" do @client.formatters_for_run.should == [[:min, nil]] end it "configures the formatter for STDOUT/STDERR" do configured_formatters = @client.configure_formatters min_formatter = configured_formatters[0] min_formatter.output.out.should == STDOUT min_formatter.output.err.should == STDERR end end context "with an output path" do before do @client = Chef::Client.new @tmpout = Tempfile.open("rspec-for-client-formatter-selection-#{Process.pid}") Chef::Config.add_formatter(:min, @tmpout.path) end after do @tmpout.close unless @tmpout.closed? @tmpout.unlink end it "configures the formatter for the file path" do configured_formatters = @client.configure_formatters min_formatter = configured_formatters[0] min_formatter.output.out.path.should == @tmpout.path min_formatter.output.err.path.should == @tmpout.path end end end end describe "run" do it "should identify the node and run ohai, then register the client" do mock_chef_rest_for_node = mock("Chef::REST (node)") mock_chef_rest_for_client = mock("Chef::REST (client)") mock_chef_rest_for_node_save = mock("Chef::REST (node save)") mock_chef_runner = mock("Chef::Runner") # --Client.register # Make sure Client#register thinks the client key doesn't # exist, so it tries to register and create one. File.should_receive(:exists?).with(Chef::Config[:client_key]).exactly(1).times.and_return(false) # Client.register will register with the validation client name. Chef::ApiClient::Registration.any_instance.should_receive(:run) # Client.register will then turn around create another # Chef::REST object, this time with the client key it got from the # previous step. Chef::REST.should_receive(:new).with(Chef::Config[:chef_server_url], @fqdn, Chef::Config[:client_key]).exactly(1).and_return(mock_chef_rest_for_node) # --Client#build_node # looks up the node, which we will return, then later saves it. Chef::Node.should_receive(:find_or_create).with(@fqdn).and_return(@node) # --ResourceReporter#node_load_completed # gets a run id from the server for storing resource history # (has its own tests, so stubbing it here.) Chef::ResourceReporter.any_instance.should_receive(:node_load_completed) # --ResourceReporter#run_completed # updates the server with the resource history # (has its own tests, so stubbing it here.) Chef::ResourceReporter.any_instance.should_receive(:run_completed) # --Client#setup_run_context # ---Client#sync_cookbooks -- downloads the list of cookbooks to sync # Chef::CookbookSynchronizer.any_instance.should_receive(:sync_cookbooks) mock_chef_rest_for_node.should_receive(:post_rest).with("environments/_default/cookbook_versions", {:run_list => []}).and_return({}) # --Client#converge Chef::Runner.should_receive(:new).and_return(mock_chef_runner) mock_chef_runner.should_receive(:converge).and_return(true) # --Client#save_updated_node Chef::REST.should_receive(:new).with(Chef::Config[:chef_server_url]).and_return(mock_chef_rest_for_node_save) mock_chef_rest_for_node_save.should_receive(:put_rest).with("nodes/#{@fqdn}", @node).and_return(true) Chef::RunLock.any_instance.should_receive(:acquire) Chef::RunLock.any_instance.should_receive(:save_pid) Chef::RunLock.any_instance.should_receive(:release) # Post conditions: check that node has been filled in correctly @client.should_receive(:run_started) @client.should_receive(:run_completed_successfully) if(Chef::Config[:client_fork] && !windows?) require 'stringio' if(Chef::Config[:pipe_node]) pipe_sim = StringIO.new pipe_sim.should_receive(:close).exactly(4).and_return(nil) res = '' pipe_sim.should_receive(:puts) do |string| res.replace(string) end pipe_sim.should_receive(:gets).and_return(res) IO.should_receive(:pipe).and_return([pipe_sim, pipe_sim]) IO.should_receive(:select).and_return(true) end proc_ret = Class.new.new proc_ret.should_receive(:success?).and_return(true) Process.should_receive(:waitpid2).and_return([1, proc_ret]) @client.should_receive(:exit).and_return(nil) @client.should_receive(:fork) do |&block| block.call end end # This is what we're testing. @client.run if(!Chef::Config[:client_fork] || Chef::Config[:pipe_node]) @node.automatic_attrs[:platform].should == "example-platform" @node.automatic_attrs[:platform_version].should == "example-platform-1.0" end end it "should remove the run_lock on failure of #load_node" do @run_lock = mock("Chef::RunLock", :acquire => true) Chef::RunLock.stub!(:new).and_return(@run_lock) @events = mock("Chef::EventDispatch::Dispatcher").as_null_object Chef::EventDispatch::Dispatcher.stub!(:new).and_return(@events) # @events is created on Chef::Client.new, so we need to recreate it after mocking @client = Chef::Client.new @client.stub!(:load_node).and_raise(Exception) @run_lock.should_receive(:release) if(Chef::Config[:client_fork] && !windows?) @client.should_receive(:fork) do |&block| block.call end end lambda { @client.run }.should raise_error(Exception) end describe "when notifying other objects of the status of the chef run" do before do Chef::Client.clear_notifications Chef::Node.stub!(:find_or_create).and_return(@node) @node.stub!(:save) @client.build_node end it "notifies observers that the run has started" do notified = false Chef::Client.when_run_starts do |run_status| run_status.node.should == @node notified = true end @client.run_started notified.should be_true end it "notifies observers that the run has completed successfully" do notified = false Chef::Client.when_run_completes_successfully do |run_status| run_status.node.should == @node notified = true end @client.run_completed_successfully notified.should be_true end it "notifies observers that the run failed" do notified = false Chef::Client.when_run_fails do |run_status| run_status.node.should == @node notified = true end @client.run_failed notified.should be_true end end end describe "build_node" do it "should expand the roles and recipes for the node" do @node.run_list << "role[role_containing_cookbook1]" role_containing_cookbook1 = Chef::Role.new role_containing_cookbook1.name("role_containing_cookbook1") role_containing_cookbook1.run_list << "cookbook1" # build_node will call Node#expand! with server, which will # eventually hit the server to expand the included role. mock_chef_rest = mock("Chef::REST") mock_chef_rest.should_receive(:get_rest).with("roles/role_containing_cookbook1").and_return(role_containing_cookbook1) Chef::REST.should_receive(:new).and_return(mock_chef_rest) # check pre-conditions. @node[:roles].should be_nil @node[:recipes].should be_nil @client.build_node # check post-conditions. @node[:roles].should_not be_nil @node[:roles].length.should == 1 @node[:roles].should include("role_containing_cookbook1") @node[:recipes].should_not be_nil @node[:recipes].length.should == 1 @node[:recipes].should include("cookbook1") end end describe "windows_admin_check" do before do @client = Chef::Client.new end context "platform is not windows" do before do Chef::Platform.stub(:windows?).and_return(false) end it "shouldn't be called" do @client.should_not_receive(:has_admin_privileges?) @client.do_windows_admin_check end end context "platform is windows" do before do Chef::Platform.stub(:windows?).and_return(true) end it "should be called" do @client.should_receive(:has_admin_privileges?) @client.do_windows_admin_check end context "admin privileges exist" do before do @client.should_receive(:has_admin_privileges?).and_return(true) end it "should not log a warning message" do Chef::Log.should_not_receive(:warn) @client.do_windows_admin_check end context "fatal admin check is configured" do it "should not raise an exception" do @client.do_windows_admin_check.should_not raise_error(Chef::Exceptions::WindowsNotAdmin) end end end context "admin privileges doesn't exist" do before do @client.should_receive(:has_admin_privileges?).and_return(false) end it "should log a warning message" do Chef::Log.should_receive(:warn) @client.do_windows_admin_check end context "fatal admin check is configured" do it "should raise an exception" do @client.do_windows_admin_check.should_not raise_error(Chef::Exceptions::WindowsNotAdmin) end end end end end describe "when a run list override is provided" do before do @node = Chef::Node.new @node.name(@fqdn) @node.chef_environment("_default") @node.automatic_attrs[:platform] = "example-platform" @node.automatic_attrs[:platform_version] = "example-platform-1.0" end it "should permit spaces in overriding run list" do @client = Chef::Client.new(nil, :override_runlist => 'role[a], role[b]') end it "should override the run list and save original runlist" do @client = Chef::Client.new(nil, :override_runlist => 'role[test_role]') @client.node = @node @node.run_list << "role[role_containing_cookbook1]" override_role = Chef::Role.new override_role.name 'test_role' override_role.run_list << 'cookbook1' original_runlist = @node.run_list.dup mock_chef_rest = mock("Chef::REST") mock_chef_rest.should_receive(:get_rest).with("roles/test_role").and_return(override_role) Chef::REST.should_receive(:new).and_return(mock_chef_rest) @node.should_receive(:save).and_return(nil) @client.build_node @node[:roles].should_not be_nil @node[:roles].should eql(['test_role']) @node[:recipes].should eql(['cookbook1']) @client.save_updated_node @node.run_list.should == original_runlist end end end describe Chef::Client do Chef::Config[:client_fork] = false it_behaves_like Chef::Client end describe "Chef::Client Forked" do before do Chef::Config[:client_fork] = true end it_behaves_like Chef::Client end chef-11.8.2/spec/unit/cookbook_spec.rb0000644000004100000410000000713412254362222017623 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::CookbookVersion do # COOKBOOK_PATH = File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "cookbooks", "openldap")) before(:each) do @cookbook_repo = File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "cookbooks")) cl = Chef::CookbookLoader.new(@cookbook_repo) cl.load_cookbooks @cookbook_collection = Chef::CookbookCollection.new(cl) @cookbook = @cookbook_collection[:openldap] @node = Chef::Node.new @node.name "JuliaChild" @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) end it "should have a name" do @cookbook.name.should == :openldap end it "should allow you to set the list of attribute files and create the mapping from short names to paths" do @cookbook.attribute_filenames = [ "attributes/one.rb", "attributes/two.rb" ] @cookbook.attribute_filenames.should == [ "attributes/one.rb", "attributes/two.rb" ] @cookbook.attribute_filenames_by_short_filename.keys.sort.should eql(["one", "two"]) @cookbook.attribute_filenames_by_short_filename["one"].should == "attributes/one.rb" @cookbook.attribute_filenames_by_short_filename["two"].should == "attributes/two.rb" end it "should allow you to set the list of recipe files and create the mapping of recipe short name to filename" do @cookbook.recipe_filenames = [ "recipes/one.rb", "recipes/two.rb" ] @cookbook.recipe_filenames.should == [ "recipes/one.rb", "recipes/two.rb" ] @cookbook.recipe_filenames_by_name.keys.sort.should eql(["one", "two"]) @cookbook.recipe_filenames_by_name["one"].should == "recipes/one.rb" @cookbook.recipe_filenames_by_name["two"].should == "recipes/two.rb" end it "should generate a list of recipes by fully-qualified name" do @cookbook.recipe_filenames = [ "recipes/one.rb", "/recipes/two.rb", "three.rb" ] @cookbook.fully_qualified_recipe_names.include?("openldap::one").should == true @cookbook.fully_qualified_recipe_names.include?("openldap::two").should == true @cookbook.fully_qualified_recipe_names.include?("openldap::three").should == true end it "should find a preferred file" do pending end it "should not return an unchanged preferred file" do pending @cookbook.preferred_filename(@node, :files, 'a-filename', 'the-checksum').should be_nil end it "should allow you to include a fully-qualified recipe using the DSL" do # DSL method include_recipe allows multiple arguments, so extract the first recipe = @run_context.include_recipe("openldap::gigantor").first recipe.recipe_name.should == "gigantor" recipe.cookbook_name.should == :openldap @run_context.resource_collection[0].name.should == "blanket" end it "should raise an ArgumentException if you try to load a bad recipe name" do lambda { @cookbook.load_recipe("doesnt_exist", @node) }.should raise_error(ArgumentError) end end chef-11.8.2/spec/unit/dsl/0000755000004100000410000000000012254362222015233 5ustar www-datawww-datachef-11.8.2/spec/unit/dsl/regsitry_helper_spec.rb0000644000004100000410000000400012254362222021773 0ustar www-datawww-data# # Author:: Prajakta Purohit () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require "chef/dsl/registry_helper" require "spec_helper" describe Chef::Resource::RegistryKey do before (:all) do events = Chef::EventDispatch::Dispatcher.new node = Chef::Node.new ohai = Ohai::System.new ohai.all_plugins node.consume_external_attrs(ohai.data,{}) run_context = Chef::RunContext.new(node, {}, events) @resource = Chef::Resource::new("foo", run_context) end context "tests registry dsl" do it "resource can access registry_helper method registry_key_exists" do @resource.respond_to?('registry_key_exists?').should == true end it "resource can access registry_helper method registry_get_values" do @resource.respond_to?('registry_get_values').should == true end it "resource can access registry_helper method registry_has_subkey" do @resource.respond_to?('registry_has_subkeys?').should == true end it "resource can access registry_helper method registry_get_subkeys" do @resource.respond_to?('registry_get_subkeys').should == true end it "resource can access registry_helper method registry_value_exists" do @resource.respond_to?('registry_value_exists?').should == true end it "resource can access registry_helper method data_value_exists" do @resource.respond_to?('registry_data_exists?').should == true end end end chef-11.8.2/spec/unit/dsl/platform_introspection_spec.rb0000644000004100000410000001171212254362222023400 0ustar www-datawww-data# # Author:: Seth Falcon () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/dsl/platform_introspection' class LanguageTester attr_reader :node def initialize(node) @node = node end include Chef::DSL::PlatformIntrospection end describe "PlatformIntrospection implementors" do let(:node) { Chef::Node.new } let(:platform_introspector) { LanguageTester.new(node) } it_behaves_like "a platform introspector" end describe Chef::DSL::PlatformIntrospection::PlatformDependentValue do before do platform_hash = { :openbsd => {:default => 'free, functional, secure'}, [:redhat, :centos, :fedora, :scientific] => {:default => '"stable"'}, :ubuntu => {'10.04' => 'using upstart more', :default => 'using init more'}, :default => 'bork da bork' } @platform_specific_value = Chef::DSL::PlatformIntrospection::PlatformDependentValue.new(platform_hash) end it "returns the default value when the platform doesn't match" do @platform_specific_value.value_for_node(:platform => :dos).should == 'bork da bork' end it "returns a value for a platform set as a group" do @platform_specific_value.value_for_node(:platform => :centos).should == '"stable"' end it "returns a value for the platform when it was set as a symbol but fetched as a string" do @platform_specific_value.value_for_node(:platform => "centos").should == '"stable"' end it "returns a value for a specific platform version" do node = {:platform => 'ubuntu', :platform_version => '10.04'} @platform_specific_value.value_for_node(node).should == 'using upstart more' end it "returns a platform-default value if the platform version doesn't match an explicit one" do node = {:platform => 'ubuntu', :platform_version => '9.10' } @platform_specific_value.value_for_node(node).should == 'using init more' end it "returns nil if there is no default and no platforms match" do # this matches the behavior in the original implementation. # whether or not it's correct is another matter. platform_specific_value = Chef::DSL::PlatformIntrospection::PlatformDependentValue.new({}) platform_specific_value.value_for_node(:platform => 'foo').should be_nil end it "raises an argument error if the platform hash is not correctly structured" do bad_hash = {:ubuntu => :foo} # should be :ubuntu => {:default => 'foo'} lambda {Chef::DSL::PlatformIntrospection::PlatformDependentValue.new(bad_hash)}.should raise_error(ArgumentError) end end describe Chef::DSL::PlatformIntrospection::PlatformFamilyDependentValue do before do @array_values = [:stop, :start, :reload] @platform_family_hash = { "debian" => "debian value", [:rhel, "fedora"] => "redhatty value", "suse" => @array_values, :gentoo => "gentoo value", :default => "default value" } @platform_family_value = Chef::DSL::PlatformIntrospection::PlatformFamilyDependentValue.new(@platform_family_hash) end it "returns the default value when the platform family doesn't match" do @platform_family_value.value_for_node(:platform_family => :os2).should == 'default value' end it "returns a value for the platform family when it was set as a string but fetched as a symbol" do @platform_family_value.value_for_node(:platform_family => :debian).should == "debian value" end it "returns a value for the platform family when it was set as a symbol but fetched as a string" do @platform_family_value.value_for_node(:platform_family => "gentoo").should == "gentoo value" end it "returns an array value stored for a platform family" do @platform_family_value.value_for_node(:platform_family => "suse").should == @array_values end it "returns a value for the platform family when it was set within an array hash key as a symbol" do @platform_family_value.value_for_node(:platform_family => :rhel).should == "redhatty value" end it "returns a value for the platform family when it was set within an array hash key as a string" do @platform_family_value.value_for_node(:platform_family => "fedora").should == "redhatty value" end it "returns nil if there is no default and no platforms match" do platform_specific_value = Chef::DSL::PlatformIntrospection::PlatformFamilyDependentValue.new({}) platform_specific_value.value_for_node(:platform_family => 'foo').should be_nil end end chef-11.8.2/spec/unit/dsl/data_query_spec.rb0000644000004100000410000000455412254362222020740 0ustar www-datawww-data# # Author:: Seth Falcon () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/dsl/data_query' class DataQueryDSLTester include Chef::DSL::DataQuery end describe Chef::DSL::DataQuery do before(:each) do @language = DataQueryDSLTester.new @node = Hash.new @language.stub!(:node).and_return(@node) end describe "when loading data bags and items" do it "lists the items in a data bag" do Chef::DataBag.should_receive(:load).with("bag_name").and_return("item_1" => "http://url_for/item_1", "item_2" => "http://url_for/item_2") @language.data_bag("bag_name").sort.should == %w[item_1 item_2] end it "validates the name of the data bag you're trying to load" do lambda {@language.data_bag("!# %^&& ")}.should raise_error(Chef::Exceptions::InvalidDataBagName) end it "fetches a data bag item" do @item = Chef::DataBagItem.new @item.data_bag("bag_name") @item.raw_data = {"id" => "item_name", "FUU" => "FUU"} Chef::DataBagItem.should_receive(:load).with("bag_name", "item_name").and_return(@item) @language.data_bag_item("bag_name", "item_name").should == @item end it "validates the name of the data bag you're trying to load an item from" do lambda {@language.data_bag_item(" %%^& ", "item_name")}.should raise_error(Chef::Exceptions::InvalidDataBagName) end it "validates the id of the data bag item you're trying to load" do lambda {@language.data_bag_item("bag_name", " 987 (*&()")}.should raise_error(Chef::Exceptions::InvalidDataBagItemID) end it "validates that the id of the data bag item is not nil" do lambda {@language.data_bag_item("bag_name", nil)}.should raise_error(Chef::Exceptions::InvalidDataBagItemID) end end end chef-11.8.2/spec/unit/handler_spec.rb0000644000004100000410000001461412254362222017433 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Handler do before(:each) do @handler = Chef::Handler.new @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_status = Chef::RunStatus.new(@node, @events) @handler.instance_variable_set(:@run_status, @run_status) end describe "when accessing the run status" do before do @backtrace = caller @exception = Exception.new("epic_fail") @exception.set_backtrace(@backtrace) @run_status.exception = @exception @run_context = Chef::RunContext.new(@node, {}, @events) @all_resources = [Chef::Resource::Cat.new('lolz'), Chef::Resource::ZenMaster.new('tzu')] @all_resources.first.updated = true @run_context.resource_collection.all_resources.replace(@all_resources) @run_status.run_context = @run_context @start_time = Time.now @end_time = @start_time + 4.2 Time.stub!(:now).and_return(@start_time, @end_time) @run_status.start_clock @run_status.stop_clock end it "has a shortcut for the exception" do @handler.exception.should == @exception end it "has a shortcut for the backtrace" do @handler.backtrace.should == @backtrace end it "has a shortcut for all resources" do @handler.all_resources.should == @all_resources end it "has a shortcut for just the updated resources" do @handler.updated_resources.should == [@all_resources.first] end it "has a shortcut for the start time" do @handler.start_time.should == @start_time end it "has a shortcut for the end time" do @handler.end_time.should == @end_time end it "has a shortcut for the elapsed time" do @handler.elapsed_time.should == 4.2 end it "has a shortcut for the node" do @handler.node.should == @node end it "has a shortcut for the run context" do @handler.run_context.should == @run_context end it "has a shortcut for the success? and failed? predicates" do @handler.success?.should be_false # becuase there's an exception @handler.failed?.should be_true end it "has a shortcut to the hash representation of the run status" do @handler.data.should == @run_status.to_hash end end describe "when running the report" do it "does not fail if the report handler raises an exception" do $report_ran = false def @handler.report $report_ran = true raise Exception, "I died the deth" end lambda {@handler.run_report_safely(@run_status)}.should_not raise_error $report_ran.should be_true end it "does not fail if the report handler does not raise an exception" do $report_ran = false def @handler.report $report_ran = true puts "I'm AOK here." end lambda {@handler.run_report_safely(@run_status)}.should_not raise_error $report_ran.should be_true end end # Hmm, no tests for report handlers, looks like describe "when running a report handler" do before do @run_context = Chef::RunContext.new(@node, {}, @events) @all_resources = [Chef::Resource::Cat.new('foo'), Chef::Resource::ZenMaster.new('moo')] @all_resources.first.updated = true @run_context.resource_collection.all_resources.replace(@all_resources) @run_status.run_context = @run_context @start_time = Time.now @end_time = @start_time + 4.2 Time.stub!(:now).and_return(@start_time, @end_time) @run_status.start_clock @run_status.stop_clock end it "has a shortcut for all resources" do @handler.all_resources.should == @all_resources end it "has a shortcut for just the updated resources" do @handler.updated_resources.should == [@all_resources.first] end it "has a shortcut for the start time" do @handler.start_time.should == @start_time end it "has a shortcut for the end time" do @handler.end_time.should == @end_time end it "has a shortcut for the elapsed time" do @handler.elapsed_time.should == 4.2 end it "has a shortcut for the node" do @handler.node.should == @node end it "has a shortcut for the run context" do @handler.run_context.should == @run_context end it "has a shortcut for the success? and failed? predicates" do @handler.success?.should be_true @handler.failed?.should be_false end it "has a shortcut to the hash representation of the run status" do @handler.data.should == @run_status.to_hash end end # and this would test the start handler describe "when running a start handler" do before do @start_time = Time.now Time.stub!(:now).and_return(@start_time) @run_status.start_clock end it "should not have all resources" do @handler.all_resources.should be_false end it "should not have updated resources" do @handler.updated_resources.should be_false end it "has a shortcut for the start time" do @handler.start_time.should == @start_time end it "does not have a shortcut for the end time" do @handler.end_time.should be_false end it "does not have a shortcut for the elapsed time" do @handler.elapsed_time.should be_false end it "has a shortcut for the node" do @handler.node.should == @node end it "does not have a shortcut for the run context" do @handler.run_context.should be_false end it "has a shortcut for the success? and failed? predicates" do @handler.success?.should be_true # for some reason this is true @handler.failed?.should be_false end it "has a shortcut to the hash representation of the run status" do @handler.data.should == @run_status.to_hash end end end chef-11.8.2/spec/unit/application_spec.rb0000644000004100000410000002223212254362222020314 0ustar www-datawww-data# # Author:: AJ Christensen () # Author:: Mark Mzyk (mmzyk@opscode.com) # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'spec_helper' describe Chef::Application do before do @original_argv = ARGV.dup ARGV.clear Chef::Log.logger = Logger.new(StringIO.new) @app = Chef::Application.new Dir.stub!(:chdir).and_return(0) @app.stub!(:reconfigure) Chef::Log.init(STDERR) end after do ARGV.replace(@original_argv) end describe "reconfigure" do before do @app = Chef::Application.new @app.stub!(:configure_chef).and_return(true) @app.stub!(:configure_logging).and_return(true) end it "should configure chef" do @app.should_receive(:configure_chef).and_return(true) @app.reconfigure end it "should configure logging" do @app.should_receive(:configure_logging).and_return(true) @app.reconfigure end end describe Chef::Application do before do @app = Chef::Application.new end describe "run" do before do @app.stub!(:setup_application).and_return(true) @app.stub!(:run_application).and_return(true) @app.stub!(:configure_chef).and_return(true) @app.stub!(:configure_logging).and_return(true) end it "should reconfigure the application before running" do @app.should_receive(:reconfigure).and_return(true) @app.run end it "should setup the application before running it" do @app.should_receive(:setup_application).and_return(true) @app.run end it "should run the actual application" do @app.should_receive(:run_application).and_return(true) @app.run end end end describe "configure_chef" do before do @app = Chef::Application.new #Chef::Config.stub!(:merge!).and_return(true) @app.stub!(:parse_options).and_return(true) end it "should parse the commandline options" do @app.should_receive(:parse_options).and_return(true) @app.config[:config_file] = "/etc/chef/default.rb" #have a config file set, to prevent triggering error block @app.configure_chef end describe "when a config_file is present" do let(:config_content) { "rspec_ran('true')" } let(:config_location) { "/etc/chef/default.rb" } let(:config_location_pathname) do p = Pathname.new(config_location) p.stub(:realpath).and_return(config_location) p end before do @app.config[:config_file] = config_location Pathname.stub(:new).with(config_location).and_return(config_location_pathname) File.should_receive(:read). with(config_location). and_return(config_content) end it "should configure chef::config from a file" do Chef::Config.should_receive(:from_string).with(config_content, config_location) @app.configure_chef end it "should merge the local config hash into chef::config" do #File.should_receive(:open).with("/etc/chef/default.rb").and_yield(@config_file) @app.configure_chef Chef::Config.rspec_ran.should == "true" end end describe "when there is no config_file defined" do before do @app.config[:config_file] = nil end it "should emit a warning" do Chef::Config.should_not_receive(:from_file).with("/etc/chef/default.rb") Chef::Log.should_receive(:warn).with("No config file found or specified on command line, using command line options.") @app.configure_chef end end describe "when the config file is set and not found" do before do @app.config[:config_file] = "/etc/chef/notfound" end it "should use the passed in command line options and defaults" do Chef::Config.should_receive(:merge!) @app.configure_chef end end end describe "when configuring the logger" do before do @app = Chef::Application.new Chef::Log.stub!(:init) end it "should initialise the chef logger" do Chef::Log.stub!(:level=) @monologger = mock("Monologger") MonoLogger.should_receive(:new).with(Chef::Config[:log_location]).and_return(@monologger) Chef::Log.should_receive(:init).with(@monologger) @app.configure_logging end shared_examples_for "log_level_is_auto" do context "when STDOUT is to a tty" do before do STDOUT.stub!(:tty?).and_return(true) end it "configures the log level to :warn" do @app.configure_logging Chef::Log.level.should == :warn end context "when force_logger is configured" do before do Chef::Config[:force_logger] = true end it "configures the log level to info" do @app.configure_logging Chef::Log.level.should == :info end end end context "when STDOUT is not to a tty" do before do STDOUT.stub!(:tty?).and_return(false) end it "configures the log level to :info" do @app.configure_logging Chef::Log.level.should == :info end context "when force_formatter is configured" do before do Chef::Config[:force_formatter] = true end it "sets the log level to :warn" do @app.configure_logging Chef::Log.level.should == :warn end end end end context "when log_level is not set" do it_behaves_like "log_level_is_auto" end context "when log_level is :auto" do before do Chef::Config[:log_level] = :auto end it_behaves_like "log_level_is_auto" end end describe "class method: fatal!" do before do STDERR.stub!(:puts).with("FATAL: blah").and_return(true) Chef::Log.stub!(:fatal).with("blah").and_return(true) Process.stub!(:exit).and_return(true) end it "should log an error message to the logger" do Chef::Log.should_receive(:fatal).with("blah").and_return(true) Chef::Application.fatal! "blah" end describe "when an exit code is supplied" do it "should exit with the given exit code" do Process.should_receive(:exit).with(-100).and_return(true) Chef::Application.fatal! "blah", -100 end end describe "when an exit code is not supplied" do it "should exit with the default exit code" do Process.should_receive(:exit).with(-1).and_return(true) Chef::Application.fatal! "blah" end end end describe "setup_application" do before do @app = Chef::Application.new end it "should raise an error" do lambda { @app.setup_application }.should raise_error(Chef::Exceptions::Application) end end describe "run_application" do before do @app = Chef::Application.new end it "should raise an error" do lambda { @app.run_application }.should raise_error(Chef::Exceptions::Application) end end context "when the config file is not available" do it "should warn for bad config file path" do @app.config[:config_file] = "/tmp/non-existing-dir/file" config_file_regexp = Regexp.new @app.config[:config_file] Chef::Log.should_receive(:warn).at_least(:once).with(config_file_regexp).and_return(true) Chef::Log.should_receive(:warn).any_number_of_times.and_return(true) @app.configure_chef end end describe "configuration errors" do before do Process.should_receive(:exit) end def raises_informative_fatals_on_configure_chef config_file_regexp = Regexp.new @app.config[:config_file] Chef::Log.should_receive(:fatal). with(/Configuration error/) Chef::Log.should_receive(:fatal). with(config_file_regexp). at_least(1).times @app.configure_chef end describe "when config file exists but contains errors" do def create_config_file(text) @config_file = Tempfile.new("rspec-chef-config") @config_file.write(text) @config_file.close @app.config[:config_file] = @config_file.path end after(:each) do @config_file.unlink end it "should raise informative fatals for missing log file dir" do create_config_file('log_location "/tmp/non-existing-dir/logfile"') raises_informative_fatals_on_configure_chef end it "should raise informative fatals for badly written config" do create_config_file("text that should break the config parsing") raises_informative_fatals_on_configure_chef end end end end chef-11.8.2/spec/unit/digester_spec.rb0000644000004100000410000000323512254362222017621 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 Opscode, Inc. # Copyright:: Copyright (c) 2009 Daniel DeLeo # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Digester do before(:each) do @cache = Chef::Digester.instance end describe "when computing checksums of cookbook files and templates" do it "proxies the class method checksum_for_file to the instance" do @cache.should_receive(:checksum_for_file).with("a_file_or_a_fail") Chef::Digester.checksum_for_file("a_file_or_a_fail") end it "computes a checksum of a file" do fixture_file = CHEF_SPEC_DATA + "/checksum/random.txt" expected = "09ee9c8cc70501763563bcf9c218d71b2fbf4186bf8e1e0da07f0f42c80a3394" @cache.checksum_for_file(fixture_file).should == expected end it "generates a checksum from a non-file IO object" do io = StringIO.new("riseofthemachines\nriseofthechefs\n") expected_md5 = '0e157ac1e2dd73191b76067fb6b4bceb' @cache.generate_md5_checksum(io).should == expected_md5 end end end chef-11.8.2/spec/unit/run_lock_spec.rb0000644000004100000410000000266112254362222017631 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require File.expand_path('../../spec_helper', __FILE__) require 'chef/client' describe Chef::RunLock do default_pid_location = windows? ? 'C:\chef\cache\chef-client-running.pid' : '/var/chef/cache/chef-client-running.pid' describe "when first created" do it "locates the lockfile in the file cache path by default" do run_lock = Chef::RunLock.new(Chef::Config.lockfile) run_lock.runlock_file.should == default_pid_location end it "locates the lockfile in the user-configured path when set" do Chef::Config.lockfile = "/tmp/chef-client-running.pid" run_lock = Chef::RunLock.new(Chef::Config.lockfile) run_lock.runlock_file.should == "/tmp/chef-client-running.pid" end end # See also: spec/functional/run_lock_spec end chef-11.8.2/spec/unit/run_status_spec.rb0000644000004100000410000001043612254362222020223 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::RunStatus do before do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @run_status = Chef::RunStatus.new(@node, @events) end describe "before the run context has been set" do it "converts to a hash" do @run_status.to_hash end end describe "when the run context has been set" do before do @run_status.run_context = @run_context end it "has a run context" do @run_status.run_context.should equal(@run_context) end it "provides access to the run context's node" do @run_status.node.should equal(@node) end it "converts to a hash" do @run_status.to_hash[:node].should equal(@node) @run_status.to_hash[:success].should be_true end describe "after it has recorded timing information" do before do @start_time = Time.new @end_time = @start_time + 23 Time.stub!(:now).and_return(@start_time, @end_time) @run_status.start_clock @run_status.stop_clock end it "records the start time of the run" do @run_status.start_time.should == @start_time end it "records the end time of the run" do @run_status.end_time.should == @end_time end it "gives the elapsed time of the chef run" do @run_status.elapsed_time.should == 23 end it "includes timing information in its hash form" do @run_status.to_hash[:start_time].should == @start_time @run_status.to_hash[:end_time].should == @end_time @run_status.to_hash[:elapsed_time].should == 23 end end describe "with resources in the resource_collection" do before do @all_resources = [Chef::Resource::Cat.new("whiskers"), Chef::Resource::ZenMaster.new('dtz')] @run_context.resource_collection.all_resources.replace(@all_resources) end it "lists all resources" do @run_status.all_resources.should == @all_resources end it "has no updated resources" do @run_status.updated_resources.should be_empty end it "includes the list of all resources in its hash form" do @run_status.to_hash[:all_resources].should == @all_resources @run_status.to_hash[:updated_resources].should be_empty end describe "and some have been updated" do before do @all_resources.first.updated = true end it "lists the updated resources" do @run_status.updated_resources.should == [@all_resources.first] end it "includes the list of updated resources in its hash form" do @run_status.to_hash[:updated_resources].should == [@all_resources.first] end end end describe "when the run failed" do before do @exception = Exception.new("just testing") @backtrace = caller @exception.set_backtrace(@backtrace) @run_status.exception = @exception end it "stores the exception" do @run_status.exception.should equal(@exception) end it "stores the backtrace" do @run_status.backtrace.should == @backtrace end it "says the run was not successful" do @run_status.success?.should be_false @run_status.failed?.should be_true end it "converts to a hash including the exception information" do @run_status.to_hash[:success].should be_false @run_status.to_hash[:exception].should == "Exception: just testing" @run_status.to_hash[:backtrace].should == @backtrace end end end end chef-11.8.2/spec/unit/shell/0000755000004100000410000000000012254362222015560 5ustar www-datawww-datachef-11.8.2/spec/unit/shell/shell_ext_spec.rb0000644000004100000410000001252012254362222021106 0ustar www-datawww-data# Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 Daniel DeLeo # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Shell::Extensions do describe "extending object for top level methods" do before do @shell_client = TestableShellSession.instance Shell.stub!(:session).and_return(@shell_client) @job_manager = TestJobManager.new @root_context = Object.new @root_context.instance_eval(&ObjectTestHarness) Shell::Extensions.extend_context_object(@root_context) @root_context.conf = mock("irbconf") end it "finds a subsession in irb for an object" do target_context_obj = Chef::Node.new irb_context = mock("context", :main => target_context_obj) irb_session = mock("irb session", :context => irb_context) @job_manager.jobs = [[:thread, irb_session]] @root_context.stub!(:jobs).and_return(@job_manager) @root_context.ensure_session_select_defined @root_context.jobs.select_shell_session(target_context_obj).should == irb_session @root_context.jobs.select_shell_session(:idontexist).should be_nil end it "finds, then switches to a session" do @job_manager.jobs = [] @root_context.stub!(:ensure_session_select_defined) @root_context.stub!(:jobs).and_return(@job_manager) @job_manager.should_receive(:select_shell_session).and_return(:the_shell_session) @job_manager.should_receive(:switch).with(:the_shell_session) @root_context.find_or_create_session_for(:foo) end it "creates a new session if an existing one isn't found" do @job_manager.jobs = [] @root_context.stub!(:jobs).and_return(@job_manager) @job_manager.stub!(:select_shell_session).and_return(nil) @root_context.should_receive(:irb).with(:foo) @root_context.find_or_create_session_for(:foo) end it "switches to recipe context" do @root_context.should respond_to(:recipe_mode) @shell_client.recipe = :monkeyTime @root_context.should_receive(:find_or_create_session_for).with(:monkeyTime) @root_context.recipe_mode end it "switches to attribute context" do @root_context.should respond_to(:attributes_mode) @shell_client.node = "monkeyNodeTime" @root_context.should_receive(:find_or_create_session_for).with("monkeyNodeTime") @root_context.attributes_mode end it "has a help command" do @root_context.should respond_to(:help) end it "turns irb tracing on and off" do @root_context.should respond_to(:trace) @root_context.conf.should_receive(:use_tracer=).with(true) @root_context.stub!(:tracing?) @root_context.tracing :on end it "says if tracing is on or off" do @root_context.conf.stub!(:use_tracer).and_return(true) @root_context.should_receive(:puts).with("tracing is on") @root_context.tracing? end it "prints node attributes" do node = mock("node", :attribute => {:foo => :bar}) @shell_client.node = node @root_context.should_receive(:pp).with({:foo => :bar}) @root_context.ohai @root_context.should_receive(:pp).with(:bar) @root_context.ohai(:foo) end it "resets the recipe and reloads ohai data" do @shell_client.should_receive(:reset!) @root_context.reset end it "turns irb echo on and off" do @root_context.conf.should_receive(:echo=).with(true) @root_context.echo :on end it "says if echo is on or off" do @root_context.conf.stub!(:echo).and_return(true) @root_context.should_receive(:puts).with("echo is on") @root_context.echo? end it "gives access to the stepable iterator" do Shell::StandAloneSession.instance.stub!(:reset!) Shell.session.stub!(:rebuild_context) events = Chef::EventDispatch::Dispatcher.new run_context = Chef::RunContext.new(Chef::Node.new, {}, events) run_context.resource_collection.instance_variable_set(:@iterator, :the_iterator) Shell.session.run_context = run_context @root_context.chef_run.should == :the_iterator end it "lists directory contents" do entries = %w{. .. someFile} Dir.should_receive(:entries).with("/tmp").and_return(entries) @root_context.ls "/tmp" end end describe "extending the recipe object" do before do @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(Chef::Node.new, {}, @events) @recipe_object = Chef::Recipe.new(nil, nil, @run_context) Shell::Extensions.extend_context_recipe(@recipe_object) end it "gives a list of the resources" do resource = @recipe_object.file("foo") @recipe_object.should_receive(:pp).with(["file[foo]"]) @recipe_object.resources end end end chef-11.8.2/spec/unit/shell/model_wrapper_spec.rb0000644000004100000410000000620012254362222021755 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'ostruct' describe Shell::ModelWrapper do before do @model = OpenStruct.new(:name=>"Chef::Node") @wrapper = Shell::ModelWrapper.new(@model) end describe "when created with an explicit model_symbol" do before do @model = OpenStruct.new(:name=>"Chef::ApiClient") @wrapper = Shell::ModelWrapper.new(@model, :client) end it "uses the explicit model symbol" do @wrapper.model_symbol.should == :client end end it "determines the model symbol from the class name" do @wrapper.model_symbol.should == :node end describe "when listing objects" do before do @node_1 = Chef::Node.new @node_1.name("sammich") @node_2 = Chef::Node.new @node_2.name("yummy") @server_response = {:node_1 => @node_1, :node_2 => @node_2} @wrapper = Shell::ModelWrapper.new(Chef::Node) Chef::Node.stub(:list).and_return(@server_response) end it "lists fully inflated objects without the resource IDs" do @wrapper.all.should have(2).nodes @wrapper.all.should include(@node_1, @node_2) end it "maps the listed nodes when given a block" do @wrapper.all {|n| n.name }.sort.reverse.should == %w{yummy sammich} end end describe "when searching for objects" do before do @node_1 = Chef::Node.new @node_1.name("sammich") @node_2 = Chef::Node.new @node_2.name("yummy") @server_response = {:node_1 => @node_1, :node_2 => @node_2} @wrapper = Shell::ModelWrapper.new(Chef::Node) # Creating a Chef::Search::Query object tries to read the private key... @searcher = mock("Chef::Search::Query #{__FILE__}:#{__LINE__}") Chef::Search::Query.stub!(:new).and_return(@searcher) end it "falls back to listing the objects when the 'query' is :all" do Chef::Node.stub(:list).and_return(@server_response) @wrapper.find(:all).should include(@node_1, @node_2) end it "searches for objects using the given query string" do @searcher.should_receive(:search).with(:node, 'name:app*').and_yield(@node_1).and_yield(@node_2) @wrapper.find("name:app*").should include(@node_1, @node_2) end it "creates a 'AND'-joined query string from a HASH" do # Hash order woes @searcher.should_receive(:search).with(:node, 'name:app* AND name:app*').and_yield(@node_1).and_yield(@node_2) @wrapper.find(:name=>"app*",'name'=>"app*").should include(@node_1, @node_2) end end end chef-11.8.2/spec/unit/shell/shell_session_spec.rb0000644000004100000410000001147212254362222021776 0ustar www-datawww-data# Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 Daniel DeLeo # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require "ostruct" class TestableShellSession < Shell::ShellSession def rebuild_node nil end def rebuild_collection nil end def loading nil end def loading_complete nil end end describe Shell::ShellSession do it "is a singleton object" do Shell::ShellSession.should include(Singleton) end end describe Shell::ClientSession do it "builds the node's run_context with the proper environment" do @session = Shell::ClientSession.instance @node = Chef::Node.build("foo") @session.node = @node @session.instance_variable_set(:@client, stub(:sync_cookbooks => {})) @expansion = Chef::RunList::RunListExpansion.new(@node.chef_environment, []) @node.run_list.should_receive(:expand).with(@node.chef_environment).and_return(@expansion) @session.rebuild_context end end describe Shell::StandAloneSession do before do @session = Shell::StandAloneSession.instance @node = @session.node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = @session.run_context = Chef::RunContext.new(@node, {}, @events) @recipe = @session.recipe = Chef::Recipe.new(nil, nil, @run_context) Shell::Extensions.extend_context_recipe(@recipe) end it "has a run_context" do @session.run_context.should equal(@run_context) end it "returns a collection based on it's standalone recipe file" do @session.resource_collection.should == @recipe.run_context.resource_collection end it "gives nil for the definitions (for now)" do @session.definitions.should be_nil end it "gives nil for the cookbook_loader" do @session.cookbook_loader.should be_nil end it "runs chef with the standalone recipe" do @session.stub!(:node_built?).and_return(true) Chef::Log.stub!(:level) chef_runner = mock("Chef::Runner.new", :converge => :converged) # pre-heat resource collection cache @session.resource_collection Chef::Runner.should_receive(:new).with(@session.recipe.run_context).and_return(chef_runner) @recipe.run_chef.should == :converged end end describe Shell::SoloSession do before do Chef::Config[:shell_solo] = true @session = Shell::SoloSession.instance @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = @session.run_context = Chef::RunContext.new(@node, {}, @events) @session.node = @node @recipe = @session.recipe = Chef::Recipe.new(nil, nil, @run_context) Shell::Extensions.extend_context_recipe(@recipe) end after do Chef::Config[:shell_solo] = nil end it "returns a collection based on it's compilation object and the extra recipe provided by chef-shell" do @session.stub!(:node_built?).and_return(true) kitteh = Chef::Resource::Cat.new("keyboard") @recipe.run_context.resource_collection << kitteh @session.resource_collection.should include(kitteh) end it "returns definitions from its compilation object" do @session.definitions.should == @run_context.definitions end it "keeps json attribs and passes them to the node for consumption" do @session.node_attributes = {"besnard_lakes" => "are_the_dark_horse"} @session.node.besnard_lakes.should == "are_the_dark_horse" #pending "1) keep attribs in an ivar 2) pass them to the node 3) feed them to the node on reset" end it "generates its resource collection from the compiled cookbooks and the ad hoc recipe" do @session.stub!(:node_built?).and_return(true) kitteh_cat = Chef::Resource::Cat.new("kitteh") @run_context.resource_collection << kitteh_cat keyboard_cat = Chef::Resource::Cat.new("keyboard_cat") @recipe.run_context.resource_collection << keyboard_cat #@session.rebuild_collection @session.resource_collection.should include(kitteh_cat, keyboard_cat) end it "runs chef with a resource collection from the compiled cookbooks" do @session.stub!(:node_built?).and_return(true) Chef::Log.stub!(:level) chef_runner = mock("Chef::Runner.new", :converge => :converged) Chef::Runner.should_receive(:new).with(an_instance_of(Chef::RunContext)).and_return(chef_runner) @recipe.run_chef.should == :converged end end chef-11.8.2/spec/unit/config_fetcher_spec.rb0000644000004100000410000000510212254362222020753 0ustar www-datawww-datarequire 'spec_helper' require 'chef/config_fetcher' describe Chef::ConfigFetcher do let(:valid_json) { {:a=>"b"}.to_json } let(:invalid_json) { %q[{"syntax-error": "missing quote}] } let(:http) { double("Chef::HTTP::Simple") } let(:config_location_regex) { Regexp.escape(config_location) } let(:invalid_json_error_regex) { %r[Could not parse the provided JSON file \(#{config_location_regex}\)] } let(:config_jail_path) { nil } let(:fetcher) { Chef::ConfigFetcher.new(config_location, config_jail_path) } context "when loading a local file" do let(:config_location) { "/etc/chef/client.rb" } let(:config_content) { "# The client.rb content" } it "reads the file from disk" do ::File.should_receive(:read). with(config_location). and_return(config_content) fetcher.read_config.should == config_content end context "and consuming JSON" do let(:config_location) { "/etc/chef/first-boot.json" } it "returns the parsed JSON" do ::File.should_receive(:read). with(config_location). and_return(valid_json) fetcher.fetch_json.should == {"a" => "b"} end context "and the JSON is invalid" do it "reports the JSON error" do ::File.should_receive(:read). with(config_location). and_return(invalid_json) Chef::Application.should_receive(:fatal!). with(invalid_json_error_regex, 2) fetcher.fetch_json end end end end context "when loading a file over HTTP" do let(:config_location) { "https://example.com/client.rb" } let(:config_content) { "# The client.rb content" } before do Chef::HTTP::Simple.should_receive(:new). with(config_location). and_return(http) end it "reads the file over HTTP" do http.should_receive(:get). with("").and_return(config_content) fetcher.read_config.should == config_content end context "and consuming JSON" do let(:config_location) { "https://example.com/foo.json" } it "fetches the file and parses it" do http.should_receive(:get). with("").and_return(valid_json) fetcher.fetch_json.should == {"a" => "b"} end context "and the JSON is invalid" do it "reports the JSON error" do http.should_receive(:get). with("").and_return(invalid_json) Chef::Application.should_receive(:fatal!). with(invalid_json_error_regex, 2) fetcher.fetch_json end end end end end chef-11.8.2/spec/unit/http/0000755000004100000410000000000012254362222015430 5ustar www-datawww-datachef-11.8.2/spec/unit/http/ssl_policies_spec.rb0000644000004100000410000001507512254362222021467 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009, 2010, 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/http/ssl_policies' describe "HTTP SSL Policy" do before do Chef::Config[:ssl_client_cert] = nil Chef::Config[:ssl_client_key] = nil Chef::Config[:ssl_ca_path] = nil Chef::Config[:ssl_ca_file] = nil end let(:unconfigured_http_client) { Net::HTTP.new("example.com", 443) } let(:http_client) do unconfigured_http_client.use_ssl = true ssl_policy.apply unconfigured_http_client end describe Chef::HTTP::DefaultSSLPolicy do let(:ssl_policy) { Chef::HTTP::DefaultSSLPolicy.new(unconfigured_http_client) } describe "when configured with :ssl_verify_mode set to :verify peer" do before do Chef::Config[:ssl_verify_mode] = :verify_peer end it "configures the HTTP client to use SSL when given a URL with the https protocol" do http_client.use_ssl?.should be_true end it "sets the OpenSSL verify mode to verify_peer" do http_client.verify_mode.should == OpenSSL::SSL::VERIFY_PEER end it "raises a ConfigurationError if :ssl_ca_path is set to a path that doesn't exist" do Chef::Config[:ssl_ca_path] = "/dev/null/nothing_here" lambda {http_client}.should raise_error(Chef::Exceptions::ConfigurationError) end it "should set the CA path if that is set in the configuration" do Chef::Config[:ssl_ca_path] = File.join(CHEF_SPEC_DATA, "ssl") http_client.ca_path.should == File.join(CHEF_SPEC_DATA, "ssl") end it "raises a ConfigurationError if :ssl_ca_file is set to a file that does not exist" do Chef::Config[:ssl_ca_file] = "/dev/null/nothing_here" lambda {http_client}.should raise_error(Chef::Exceptions::ConfigurationError) end it "should set the CA file if that is set in the configuration" do Chef::Config[:ssl_ca_file] = CHEF_SPEC_DATA + '/ssl/5e707473.0' http_client.ca_file.should == CHEF_SPEC_DATA + '/ssl/5e707473.0' end end describe "when configured with :ssl_verify_mode set to :verify peer" do before do @url = URI.parse("https://chef.example.com:4443/") Chef::Config[:ssl_verify_mode] = :verify_none end it "sets the OpenSSL verify mode to :verify_none" do http_client.verify_mode.should == OpenSSL::SSL::VERIFY_NONE end end describe "when configured with a client certificate" do before {@url = URI.parse("https://chef.example.com:4443/")} it "raises ConfigurationError if the certificate file doesn't exist" do Chef::Config[:ssl_client_cert] = "/dev/null/nothing_here" Chef::Config[:ssl_client_key] = CHEF_SPEC_DATA + '/ssl/chef-rspec.key' lambda {http_client}.should raise_error(Chef::Exceptions::ConfigurationError) end it "raises ConfigurationError if the certificate file doesn't exist" do Chef::Config[:ssl_client_cert] = CHEF_SPEC_DATA + '/ssl/chef-rspec.cert' Chef::Config[:ssl_client_key] = "/dev/null/nothing_here" lambda {http_client}.should raise_error(Chef::Exceptions::ConfigurationError) end it "raises a ConfigurationError if one of :ssl_client_cert and :ssl_client_key is set but not both" do Chef::Config[:ssl_client_cert] = "/dev/null/nothing_here" Chef::Config[:ssl_client_key] = nil lambda {http_client}.should raise_error(Chef::Exceptions::ConfigurationError) end it "configures the HTTP client's cert and private key" do Chef::Config[:ssl_client_cert] = CHEF_SPEC_DATA + '/ssl/chef-rspec.cert' Chef::Config[:ssl_client_key] = CHEF_SPEC_DATA + '/ssl/chef-rspec.key' http_client.cert.to_s.should == OpenSSL::X509::Certificate.new(IO.read(CHEF_SPEC_DATA + '/ssl/chef-rspec.cert')).to_s http_client.key.to_s.should == IO.read(CHEF_SPEC_DATA + '/ssl/chef-rspec.key') end end context "when additional certs are located in the trusted_certs dir" do let(:self_signed_crt_path) { File.join(CHEF_SPEC_DATA, "trusted_certs", "example.crt") } let(:self_signed_crt) { OpenSSL::X509::Certificate.new(File.read(self_signed_crt_path)) } let(:additional_pem_path) { File.join(CHEF_SPEC_DATA, "trusted_certs", "opscode.pem") } let(:additional_pem) { OpenSSL::X509::Certificate.new(File.read(additional_pem_path)) } before do Chef::Config.trusted_certs_dir = File.join(CHEF_SPEC_DATA, "trusted_certs") end it "enables verification of self-signed certificates" do http_client.cert_store.verify(self_signed_crt).should be_true end it "enables verification of cert chains" do # This cert is signed by DigiCert so it would be valid in normal SSL usage. # The chain goes: # trusted root -> intermediate -> opscode.pem # In this test, the intermediate has to be loaded and trusted in order # for verification to work correctly. # If the machine running the test doesn't have ruby SSL configured correctly, # then the root cert also has to be loaded for the test to succeed. # The system under test **SHOULD** do both of these things. http_client.cert_store.verify(additional_pem).should be_true end context "and some certs are duplicates" do it "skips duplicate certs" do # For whatever reason, OpenSSL errors out when adding a # cert you already have to the certificate store. ssl_policy.set_custom_certs ssl_policy.set_custom_certs #should not raise an error end end end end describe Chef::HTTP::APISSLPolicy do let(:ssl_policy) { Chef::HTTP::APISSLPolicy.new(unconfigured_http_client) } context "when verify_api_cert is set" do before do Chef::Config[:verify_api_cert] = true end it "sets the OpenSSL verify mode to verify_peer" do http_client.verify_mode.should == OpenSSL::SSL::VERIFY_PEER end end end end chef-11.8.2/spec/unit/handler/0000755000004100000410000000000012254362222016066 5ustar www-datawww-datachef-11.8.2/spec/unit/handler/json_file_spec.rb0000644000004100000410000000436012254362222021400 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Handler::JsonFile do before(:each) do @handler = Chef::Handler::JsonFile.new(:the_sun => "will rise", :path => '/tmp/foobarbazqux') end it "accepts arbitrary config options" do @handler.config[:the_sun].should == "will rise" end it "creates the directory where the reports will be saved" do FileUtils.should_receive(:mkdir_p).with('/tmp/foobarbazqux') File.should_receive(:chmod).with(00700, '/tmp/foobarbazqux') @handler.build_report_dir end describe "when reporting success" do before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_status = Chef::RunStatus.new(@node, @events) @expected_time = Time.now Time.stub(:now).and_return(@expected_time, @expected_time + 5) @run_status.start_clock @run_status.stop_clock @run_context = Chef::RunContext.new(@node, {}, @events) @run_status.run_context = @run_context @run_status.exception = Exception.new("Boy howdy!") @file_mock = StringIO.new File.stub!(:open).and_yield(@file_mock) end it "saves run status data to a file as JSON" do @handler.should_receive(:build_report_dir) @handler.run_report_unsafe(@run_status) reported_data = Chef::JSONCompat.from_json(@file_mock.string) reported_data['exception'].should == "Exception: Boy howdy!" reported_data['start_time'].should == @expected_time.to_s reported_data['end_time'].should == (@expected_time + 5).to_s reported_data['elapsed_time'].should == 5 end end end chef-11.8.2/spec/unit/version_class_spec.rb0000644000004100000410000001275112254362222020670 0ustar www-datawww-data# # Author:: Seth Falcon () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'spec_helper' require 'chef/version_class' describe Chef::Version do before do @v0 = Chef::Version.new "0.0.0" @v123 = Chef::Version.new "1.2.3" end it "should turn itself into a string" do @v0.to_s.should == "0.0.0" @v123.to_s.should == "1.2.3" end it "should make a round trip with its string representation" do a = Chef::Version.new(@v123.to_s) a.should == @v123 end it "should transform 1.2 to 1.2.0" do Chef::Version.new("1.2").to_s.should == "1.2.0" end it "should transform 01.002.0003 to 1.2.3" do a = Chef::Version.new "01.002.0003" a.should == @v123 end describe "when creating valid Versions" do good_versions = %w(1.2 1.2.3 1000.80.50000 0.300.25 001.02.00003) good_versions.each do |v| it "should accept '#{v}'" do Chef::Version.new v end end end describe "when given bogus input" do bad_versions = ["1.2.3.4", "1.2.a4", "1", "a", "1.2 3", "1.2 a", "1 2 3", "1-2-3", "1_2_3", "1.2_3", "1.2-3"] the_error = Chef::Exceptions::InvalidCookbookVersion bad_versions.each do |v| it "should raise #{the_error} when given '#{v}'" do lambda { Chef::Version.new v }.should raise_error(the_error) end end end describe "<=>" do it "should equate versions 1.2 and 1.2.0" do Chef::Version.new("1.2").should == Chef::Version.new("1.2.0") end it "should equate version 1.04 and 1.4" do Chef::Version.new("1.04").should == Chef::Version.new("1.4") end it "should treat versions as numbers in the right way" do Chef::Version.new("2.0").should be < Chef::Version.new("11.0") end it "should sort based on the version number" do examples = [ # smaller, larger ["1.0", "2.0"], ["1.2.3", "1.2.4"], ["1.2.3", "1.3.0"], ["1.2.3", "1.3"], ["1.2.3", "2.1.1"], ["1.2.3", "2.1"], ["1.2", "1.2.4"], ["1.2", "1.3.0"], ["1.2", "1.3"], ["1.2", "2.1.1"], ["1.2", "2.1"] ] examples.each do |smaller, larger| sm = Chef::Version.new(smaller) lg = Chef::Version.new(larger) sm.should be < lg lg.should be > sm sm.should_not == lg end end it "should sort an array of versions" do a = %w{0.0.0 0.0.1 0.1.0 0.1.1 1.0.0 1.1.0 1.1.1}.map do |s| Chef::Version.new(s) end got = a.sort.map {|v| v.to_s } got.should == %w{0.0.0 0.0.1 0.1.0 0.1.1 1.0.0 1.1.0 1.1.1} end it "should sort an array of versions, part 2" do a = %w{9.8.7 1.0.0 1.2.3 4.4.6 4.5.6 0.8.6 4.5.5 5.9.8 3.5.7}.map do |s| Chef::Version.new(s) end got = a.sort.map { |v| v.to_s } got.should == %w{0.8.6 1.0.0 1.2.3 3.5.7 4.4.6 4.5.5 4.5.6 5.9.8 9.8.7} end describe "comparison examples" do [ [ "0.0.0", :>, "0.0.0", false ], [ "0.0.0", :>=, "0.0.0", true ], [ "0.0.0", :==, "0.0.0", true ], [ "0.0.0", :<=, "0.0.0", true ], [ "0.0.0", :<, "0.0.0", false ], [ "0.0.0", :>, "0.0.1", false ], [ "0.0.0", :>=, "0.0.1", false ], [ "0.0.0", :==, "0.0.1", false ], [ "0.0.0", :<=, "0.0.1", true ], [ "0.0.0", :<, "0.0.1", true ], [ "0.0.1", :>, "0.0.1", false ], [ "0.0.1", :>=, "0.0.1", true ], [ "0.0.1", :==, "0.0.1", true ], [ "0.0.1", :<=, "0.0.1", true ], [ "0.0.1", :<, "0.0.1", false ], [ "0.1.0", :>, "0.1.0", false ], [ "0.1.0", :>=, "0.1.0", true ], [ "0.1.0", :==, "0.1.0", true ], [ "0.1.0", :<=, "0.1.0", true ], [ "0.1.0", :<, "0.1.0", false ], [ "0.1.1", :>, "0.1.1", false ], [ "0.1.1", :>=, "0.1.1", true ], [ "0.1.1", :==, "0.1.1", true ], [ "0.1.1", :<=, "0.1.1", true ], [ "0.1.1", :<, "0.1.1", false ], [ "1.0.0", :>, "1.0.0", false ], [ "1.0.0", :>=, "1.0.0", true ], [ "1.0.0", :==, "1.0.0", true ], [ "1.0.0", :<=, "1.0.0", true ], [ "1.0.0", :<, "1.0.0", false ], [ "1.0.0", :>, "0.0.1", true ], [ "1.0.0", :>=, "1.9.2", false ], [ "1.0.0", :==, "9.7.2", false ], [ "1.0.0", :<=, "1.9.1", true ], [ "1.0.0", :<, "1.9.0", true ], [ "1.2.2", :>, "1.2.1", true ], [ "1.2.2", :>=, "1.2.1", true ], [ "1.2.2", :==, "1.2.1", false ], [ "1.2.2", :<=, "1.2.1", false ], [ "1.2.2", :<, "1.2.1", false ] ].each do |spec| it "(#{spec.first(3).join(' ')}) should be #{spec[3]}" do got = Chef::Version.new(spec[0]).send(spec[1], Chef::Version.new(spec[2])) got.should == spec[3] end end end end end chef-11.8.2/spec/unit/resource_reporter_spec.rb0000644000004100000410000005731212254362222021571 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Author:: Prajakta Purohit () # Author:: Tyler Cloke () # # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require File.expand_path("../../spec_helper", __FILE__) require 'chef/resource_reporter' describe Chef::ResourceReporter do before(:all) do @reporting_toggle_default = Chef::Config[:enable_reporting] Chef::Config[:enable_reporting] = true end after(:all) do Chef::Config[:enable_reporting] = @reporting_toggle_default end before do @node = Chef::Node.new @node.name("spitfire") @rest_client = mock("Chef::REST (mock)") @rest_client.stub!(:post_rest).and_return(true) @resource_reporter = Chef::ResourceReporter.new(@rest_client) @run_id = @resource_reporter.run_id @new_resource = Chef::Resource::File.new("/tmp/a-file.txt") @new_resource.cookbook_name = "monkey" @cookbook_version = mock("Cookbook::Version", :version => "1.2.3") @new_resource.stub!(:cookbook_version).and_return(@cookbook_version) @current_resource = Chef::Resource::File.new("/tmp/a-file.txt") @start_time = Time.new @end_time = Time.new + 20 @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @run_status = Chef::RunStatus.new(@node, @events) Time.stub!(:now).and_return(@start_time, @end_time) end context "when first created" do it "has no updated resources" do @resource_reporter.should have(0).updated_resources end it "reports a successful run" do @resource_reporter.status.should == "success" end it "assumes the resource history feature is supported" do @resource_reporter.reporting_enabled?.should be_true end it "should have no error_descriptions" do @resource_reporter.error_descriptions.should eq({}) # @resource_reporter.error_descriptions.should be_empty # @resource_reporter.should have(0).error_descriptions end end context "after the chef run completes" do before do end it "reports a successful run" do pending "refactor how node gets set." @resource_reporter.status.should == "success" end end context "when chef fails" do before do @rest_client.stub!(:create_url).and_return("reports/nodes/spitfire/runs/#{@run_id}"); @rest_client.stub!(:raw_http_request).and_return({"result"=>"ok"}); @rest_client.stub!(:post_rest).and_return({"uri"=>"https://example.com/reports/nodes/spitfire/runs/#{@run_id}"}); end context "before converging any resources" do before do @resource_reporter.run_started(@run_status) @exception = Exception.new @resource_reporter.run_failed(@exception) end it "sets the run status to 'failure'" do @resource_reporter.status.should == "failure" end it "keeps the exception data" do @resource_reporter.exception.should == @exception end end context "when a resource fails before loading current state" do before do @exception = Exception.new @exception.set_backtrace(caller) @resource_reporter.resource_action_start(@new_resource, :create) @resource_reporter.resource_failed(@new_resource, :create, @exception) @resource_reporter.resource_completed(@new_resource) end it "collects the resource as an updated resource" do @resource_reporter.should have(1).updated_resources end it "collects the desired state of the resource" do update_record = @resource_reporter.updated_resources.first update_record.new_resource.should == @new_resource end end # TODO: make sure a resource that is skipped because of `not_if` doesn't # leave us in a bad state. context "once the a resource's current state is loaded" do before do @resource_reporter.resource_action_start(@new_resource, :create) @resource_reporter.resource_current_state_loaded(@new_resource, :create, @current_resource) end context "and the resource was not updated" do before do @resource_reporter.resource_up_to_date(@new_resource, :create) end it "has no updated resources" do @resource_reporter.should have(0).updated_resources end end context "and the resource was updated" do before do @new_resource.content("this is the old content") @current_resource.content("this is the new hotness") @resource_reporter.resource_updated(@new_resource, :create) @resource_reporter.resource_completed(@new_resource) end it "collects the updated resource" do @resource_reporter.should have(1).updated_resources end it "collects the old state of the resource" do update_record = @resource_reporter.updated_resources.first update_record.current_resource.should == @current_resource end it "collects the new state of the resource" do update_record = @resource_reporter.updated_resources.first update_record.new_resource.should == @new_resource end context "and a subsequent resource fails before loading current resource" do before do @next_new_resource = Chef::Resource::Service.new("apache2") @exception = Exception.new @exception.set_backtrace(caller) @resource_reporter.resource_failed(@next_new_resource, :create, @exception) @resource_reporter.resource_completed(@next_new_resource) end it "collects the desired state of the failed resource" do failed_resource_update = @resource_reporter.updated_resources.last failed_resource_update.new_resource.should == @next_new_resource end it "does not have the current state of the failed resource" do failed_resource_update = @resource_reporter.updated_resources.last failed_resource_update.current_resource.should be_nil end end end # Some providers, such as RemoteDirectory and some LWRPs use other # resources for their implementation. These should be hidden from reporting # since we only care about the top-level resource and not the sub-resources # used for implementation. context "and a nested resource is updated" do before do @implementation_resource = Chef::Resource::CookbookFile.new("/preseed-file.txt") @resource_reporter.resource_action_start(@implementation_resource , :create) @resource_reporter.resource_current_state_loaded(@implementation_resource, :create, @implementation_resource) @resource_reporter.resource_updated(@implementation_resource, :create) @resource_reporter.resource_completed(@implementation_resource) @resource_reporter.resource_updated(@new_resource, :create) @resource_reporter.resource_completed(@new_resource) end it "does not collect data about the nested resource" do @resource_reporter.should have(1).updated_resources end end context "and a nested resource runs but is not updated" do before do @implementation_resource = Chef::Resource::CookbookFile.new("/preseed-file.txt") @resource_reporter.resource_action_start(@implementation_resource , :create) @resource_reporter.resource_current_state_loaded(@implementation_resource, :create, @implementation_resource) @resource_reporter.resource_up_to_date(@implementation_resource, :create) @resource_reporter.resource_completed(@implementation_resource) @resource_reporter.resource_updated(@new_resource, :create) @resource_reporter.resource_completed(@new_resource) end it "does not collect data about the nested resource" do @resource_reporter.should have(1).updated_resources end end context "and the resource failed to converge" do before do @exception = Exception.new @exception.set_backtrace(caller) @resource_reporter.resource_failed(@new_resource, :create, @exception) @resource_reporter.resource_completed(@new_resource) end it "collects the resource as an updated resource" do @resource_reporter.should have(1).updated_resources end it "collects the desired state of the resource" do update_record = @resource_reporter.updated_resources.first update_record.new_resource.should == @new_resource end it "collects the current state of the resource" do update_record = @resource_reporter.updated_resources.first update_record.current_resource.should == @current_resource end end end end describe "when generating a report for the server" do before do @rest_client.stub!(:create_url).and_return("reports/nodes/spitfire/runs/#{@run_id}"); @rest_client.stub!(:raw_http_request).and_return({"result"=>"ok"}); @rest_client.stub!(:post_rest).and_return({"uri"=>"https://example.com/reports/nodes/spitfire/runs/#{@run_id}"}); @resource_reporter.run_started(@run_status) end context "for a successful client run" do before do # TODO: add inputs to generate expected output. # expected_data = { # "action" : "end", # "resources" : [ # { # "type" : "file", # "id" : "/etc/passwd", # "name" : "User Defined Resource Block Name", # "duration" : "1200", # "result" : "modified", # "before" : { # "state" : "exists", # "group" : "root", # "owner" : "root", # "checksum" : "xyz" # }, # "after" : { # "state" : "modified", # "group" : "root", # "owner" : "root", # "checksum" : "abc" # }, # "delta" : "" # }, # {...} # ], # "status" : "success" # "data" : "" # } @resource_reporter.resource_action_start(@new_resource, :create) @resource_reporter.resource_current_state_loaded(@new_resource, :create, @current_resource) @resource_reporter.resource_updated(@new_resource, :create) @resource_reporter.resource_completed(@new_resource) @run_status.stop_clock @report = @resource_reporter.prepare_run_data @first_update_report = @report["resources"].first end it "includes the run's status" do @report.should have_key("status") end it "includes a list of updated resources" do @report.should have_key("resources") end it "includes an updated resource's type" do @first_update_report.should have_key("type") end it "includes an updated resource's initial state" do @first_update_report["before"].should == @current_resource.state end it "includes an updated resource's final state" do @first_update_report["after"].should == @new_resource.state end it "includes the resource's name" do @first_update_report["name"].should == @new_resource.name end it "includes the resource's id attribute" do @first_update_report["id"].should == @new_resource.identity end it "includes the elapsed time for the resource to converge" do # TODO: API takes integer number of milliseconds as a string. This # should be an int. @first_update_report.should have_key("duration") @first_update_report["duration"].to_i.should be_within(100).of(0) end it "includes the action executed by the resource" do # TODO: rename as "action" @first_update_report["result"].should == "create" end it "includes the cookbook name of the resource" do @first_update_report.should have_key("cookbook_name") @first_update_report["cookbook_name"].should == "monkey" end it "includes the cookbook version of the resource" do @first_update_report.should have_key("cookbook_version") @first_update_report["cookbook_version"].should == "1.2.3" end it "includes the total resource count" do @report.should have_key("total_res_count") @report["total_res_count"].should == "1" end it "includes the data hash" do @report.should have_key("data") @report["data"].should == {} end it "includes the run_list" do @report.should have_key("run_list") @report["run_list"].should == @run_status.node.run_list.to_json end it "includes the end_time" do @report.should have_key("end_time") @report["end_time"].should == @run_status.end_time.to_s end end context "for an unsuccessful run" do before do @backtrace = ["foo.rb:1 in `foo!'","bar.rb:2 in `bar!","'baz.rb:3 in `baz!'"] @node = Chef::Node.new @node.name("spitfire") @exception = mock("ArgumentError") @exception.stub!(:inspect).and_return("Net::HTTPServerException") @exception.stub!(:message).and_return("Object not found") @exception.stub!(:backtrace).and_return(@backtrace) @resource_reporter.run_list_expand_failed(@node, @exception) @resource_reporter.run_failed(@exception) @report = @resource_reporter.prepare_run_data end it "includes the exception type in the event data" do @report.should have_key("data") @report["data"]["exception"].should have_key("class") @report["data"]["exception"]["class"].should == "Net::HTTPServerException" end it "includes the exception message in the event data" do @report["data"]["exception"].should have_key("message") @report["data"]["exception"]["message"].should == "Object not found" end it "includes the exception trace in the event data" do @report["data"]["exception"].should have_key("backtrace") @report["data"]["exception"]["backtrace"].should == @backtrace.to_json end it "includes the error inspector output in the event data" do @report["data"]["exception"].should have_key("description") @report["data"]["exception"]["description"].should include({"title"=>"Error expanding the run_list:", "sections"=>[{"Unexpected Error:" => "RSpec::Mocks::Mock: Object not found"}]}) end end context "when new_resource does not have a cookbook_name" do before do @bad_resource = Chef::Resource::File.new("/tmp/a-file.txt") @bad_resource.cookbook_name = nil @resource_reporter.resource_action_start(@bad_resource, :create) @resource_reporter.resource_current_state_loaded(@bad_resource, :create, @current_resource) @resource_reporter.resource_updated(@bad_resource, :create) @resource_reporter.resource_completed(@bad_resource) @run_status.stop_clock @report = @resource_reporter.prepare_run_data @first_update_report = @report["resources"].first end it "includes an updated resource's initial state" do @first_update_report["before"].should == @current_resource.state end it "includes an updated resource's final state" do @first_update_report["after"].should == @new_resource.state end it "includes the resource's name" do @first_update_report["name"].should == @new_resource.name end it "includes the resource's id attribute" do @first_update_report["id"].should == @new_resource.identity end it "includes the elapsed time for the resource to converge" do # TODO: API takes integer number of milliseconds as a string. This # should be an int. @first_update_report.should have_key("duration") @first_update_report["duration"].to_i.should be_within(100).of(0) end it "includes the action executed by the resource" do # TODO: rename as "action" @first_update_report["result"].should == "create" end it "does not include a cookbook name for the resource" do @first_update_report.should_not have_key("cookbook_name") end it "does not include a cookbook version for the resource" do @first_update_report.should_not have_key("cookbook_version") end end context "when including a resource that overrides Resource#state" do before do @current_state_resource = Chef::Resource::WithState.new("Stateful", @run_context) @current_state_resource.state = nil @new_state_resource = Chef::Resource::WithState.new("Stateful", @run_context) @new_state_resource.state = "Running" @resource_reporter.resource_action_start(@new_state_resource, :create) @resource_reporter.resource_current_state_loaded(@new_state_resource, :create, @current_state_resource) @resource_reporter.resource_updated(@new_state_resource, :create) @resource_reporter.resource_completed(@new_state_resource) @run_status.stop_clock @report = @resource_reporter.prepare_run_data @first_update_report = @report["resources"].first end it "sets before to {} instead of nil" do @first_update_report.should have_key("before") @first_update_report['before'].should eq({}) end it "sets after to {} instead of 'Running'" do @first_update_report.should have_key("after") @first_update_report['after'].should eq({}) end end end describe "when updating resource history on the server" do before do @resource_reporter.run_started(@run_status) @run_status.start_clock end context "when the server does not support storing resource history" do before do # 404 getting the run_id @response = Net::HTTPNotFound.new("a response body", "404", "Not Found") @error = Net::HTTPServerException.new("404 message", @response) @rest_client.should_receive(:post_rest). with("reports/nodes/spitfire/runs", {:action => :start, :run_id => @run_id, :start_time => @start_time.to_s}, {'X-Ops-Reporting-Protocol-Version' => Chef::ResourceReporter::PROTOCOL_VERSION}). and_raise(@error) end it "assumes the feature is not enabled" do @resource_reporter.run_started(@run_status) @resource_reporter.reporting_enabled?.should be_false end it "does not send a resource report to the server" do @resource_reporter.run_started(@run_status) @rest_client.should_not_receive(:post_rest) @resource_reporter.run_completed(@node) end it "prints an error about the 404" do Chef::Log.should_receive(:debug).with(/404/) @resource_reporter.run_started(@run_status) end end context "when the server returns a 500 to the client" do before do # 500 getting the run_id @response = Net::HTTPInternalServerError.new("a response body", "500", "Internal Server Error") @error = Net::HTTPServerException.new("500 message", @response) @rest_client.should_receive(:post_rest). with("reports/nodes/spitfire/runs", {:action => :start, :run_id => @run_id, :start_time => @start_time.to_s}, {'X-Ops-Reporting-Protocol-Version' => Chef::ResourceReporter::PROTOCOL_VERSION}). and_raise(@error) end it "assumes the feature is not enabled" do @resource_reporter.run_started(@run_status) @resource_reporter.reporting_enabled?.should be_false end it "does not send a resource report to the server" do @resource_reporter.run_started(@run_status) @rest_client.should_not_receive(:post_rest) @resource_reporter.run_completed(@node) end it "prints an error about the error" do Chef::Log.should_receive(:info).with(/500/) @resource_reporter.run_started(@run_status) end end context "when the server returns a 500 to the client and enable_reporting_url_fatals is true" do before do @enable_reporting_url_fatals = Chef::Config[:enable_reporting_url_fatals] Chef::Config[:enable_reporting_url_fatals] = true # 500 getting the run_id @response = Net::HTTPInternalServerError.new("a response body", "500", "Internal Server Error") @error = Net::HTTPServerException.new("500 message", @response) @rest_client.should_receive(:post_rest). with("reports/nodes/spitfire/runs", {:action => :start, :run_id => @run_id, :start_time => @start_time.to_s}, {'X-Ops-Reporting-Protocol-Version' => Chef::ResourceReporter::PROTOCOL_VERSION}). and_raise(@error) end after do Chef::Config[:enable_reporting_url_fatals] = @enable_reporting_url_fatals end it "fails the run and prints an message about the error" do Chef::Log.should_receive(:error).with(/500/) lambda { @resource_reporter.run_started(@run_status) }.should raise_error(Net::HTTPServerException) end end context "after creating the run history document" do before do response = {"uri"=>"https://example.com/reports/nodes/spitfire/runs/@run_id"} @rest_client.should_receive(:post_rest). with("reports/nodes/spitfire/runs", {:action => :start, :run_id => @run_id, :start_time => @start_time.to_s}, {'X-Ops-Reporting-Protocol-Version' => Chef::ResourceReporter::PROTOCOL_VERSION}). and_return(response) @resource_reporter.run_started(@run_status) end it "creates a run document on the server at the start of the run" do @resource_reporter.run_id.should == @run_id end it "updates the run document with resource updates at the end of the run" do # update some resources... @resource_reporter.resource_action_start(@new_resource, :create) @resource_reporter.resource_current_state_loaded(@new_resource, :create, @current_resource) @resource_reporter.resource_updated(@new_resource, :create) @resource_reporter.stub!(:end_time).and_return(@end_time) @expected_data = @resource_reporter.prepare_run_data post_url = "https://chef_server/example_url" response = {"result"=>"ok"} @rest_client.should_receive(:create_url). with("reports/nodes/spitfire/runs/#{@run_id}"). ordered. and_return(post_url) @rest_client.should_receive(:raw_http_request).ordered do |method, url, headers, data| method.should eq(:POST) url.should eq(post_url) headers.should eq({'Content-Encoding' => 'gzip', 'X-Ops-Reporting-Protocol-Version' => Chef::ResourceReporter::PROTOCOL_VERSION }) data_stream = Zlib::GzipReader.new(StringIO.new(data)) data = data_stream.read data.should eq(@expected_data.to_json) response end @resource_reporter.run_completed(@node) end end end end chef-11.8.2/spec/unit/util/0000755000004100000410000000000012254362222015426 5ustar www-datawww-datachef-11.8.2/spec/unit/util/diff_spec.rb0000644000004100000410000004307512254362222017706 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'tmpdir' shared_context "using file paths with spaces" do let!(:old_tempfile) { Tempfile.new("chef-util diff-spec") } let!(:new_tempfile) { Tempfile.new("chef-util diff-spec") } end shared_context "using file paths without spaces" do let!(:old_tempfile) { Tempfile.new("chef-util-diff-spec") } let!(:new_tempfile) { Tempfile.new("chef-util-diff-spec") } end shared_examples_for "a diff util" do it "should return a Chef::Util::Diff" do expect(differ).to be_a_kind_of(Chef::Util::Diff) end it "produces a diff even if the old_file does not exist" do old_tempfile.close old_tempfile.unlink expect(differ.for_output).to eql(["(no diff)"]) end it "produces a diff even if the new_file does not exist" do new_tempfile.close new_tempfile.unlink expect(differ.for_output).to eql(["(no diff)"]) end describe "when the two files exist with no content" do it "calling for_output should return the error message" do expect(differ.for_output).to eql(["(no diff)"]) end it "calling for_reporting should be nil" do expect(differ.for_reporting).to be_nil end end describe "when diffs are disabled" do before do Chef::Config[:diff_disabled] = true end after do Chef::Config[:diff_disabled] = false end it "calling for_output should return the error message" do expect(differ.for_output).to eql( [ "(diff output suppressed by config)" ] ) end it "calling for_reporting should be nil" do expect(differ.for_reporting).to be_nil end end describe "when the old_file has binary content" do before do old_tempfile.write("\x01\xff") old_tempfile.close end it "calling for_output should return the error message" do expect(differ.for_output).to eql( [ "(current file is binary, diff output suppressed)" ] ) end it "calling for_reporting should be nil" do expect(differ.for_reporting).to be_nil end end describe "when the new_file has binary content" do before do new_tempfile.write("\x01\xff") new_tempfile.close end it "calling for_output should return the error message" do expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ]) end it "calling for_reporting should be nil" do expect(differ.for_reporting).to be_nil end end describe "when the default external encoding is UTF-8", :ruby_gte_19_only do before do @saved_default_external = Encoding.default_external Encoding.default_external = Encoding::UTF_8 end after do Encoding.default_external = @saved_default_external end describe "when a file has ASCII text" do before do new_tempfile.write(plain_ascii) new_tempfile.close end it "calling for_output should return a valid diff" do differ.for_output.join("\\n").should match(/\A--- .*\\n\+\+\+ .*\\n@@/m) end it "calling for_reporting should return a utf-8 string" do expect(differ.for_reporting.encoding).to equal(Encoding::UTF_8) end end describe "when a file has UTF-8 text" do before do new_tempfile.write(utf_8) new_tempfile.close end it "calling for_output should return a valid diff" do differ.for_output.join("\\n").should match(/\A--- .*\\n\+\+\+ .*\\n@@/m) end it "calling for_reporting should return a utf-8 string" do expect(differ.for_reporting.encoding).to equal(Encoding::UTF_8) end end describe "when a file has Latin-1 text" do before do new_tempfile.write(latin_1) new_tempfile.close end it "calling for_output should complain that the content is binary" do expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ]) end it "calling for_reporting should be nil" do expect(differ.for_reporting).to be_nil end end describe "when a file has Shift-JIS text" do before do new_tempfile.write(shift_jis) new_tempfile.close end it "calling for_output should complain that the content is binary" do expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ]) end it "calling for_reporting should be nil" do expect(differ.for_reporting).to be_nil end end end describe "when the default external encoding is Latin-1", :ruby_gte_19_only do before do @saved_default_external = Encoding.default_external Encoding.default_external = Encoding::ISO_8859_1 end after do Encoding.default_external = @saved_default_external end describe "when a file has ASCII text" do before do new_tempfile.write(plain_ascii) new_tempfile.close end it "calling for_output should return a valid diff" do differ.for_output.join("\\n").should match(/\A--- .*\\n\+\+\+ .*\\n@@/m) end it "calling for_reporting should return a utf-8 string" do expect(differ.for_reporting.encoding).to equal(Encoding::UTF_8) end end describe "when a file has UTF-8 text" do before do new_tempfile.write(utf_8) new_tempfile.close end it "calling for_output should complain that the content is binary" do expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ]) end it "calling for_reporting should be nil" do expect(differ.for_reporting).to be_nil end end describe "when a file has Latin-1 text" do before do new_tempfile.write(latin_1) new_tempfile.close end it "calling for_output should return a valid diff" do differ.for_output.join("\\n").should match(/\A--- .*\\n\+\+\+ .*\\n@@/m) end it "calling for_reporting should return a utf-8 string" do expect(differ.for_reporting.encoding).to equal(Encoding::UTF_8) end end describe "when a file has Shift-JIS text" do before do new_tempfile.write(shift_jis) new_tempfile.close end it "calling for_output should complain that the content is binary" do expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ]) end it "calling for_reporting should be nil" do expect(differ.for_reporting).to be_nil end end end describe "when the default external encoding is Shift_JIS", :ruby_gte_19_only do before do @saved_default_external = Encoding.default_external Encoding.default_external = Encoding::Shift_JIS end after do Encoding.default_external = @saved_default_external end describe "when a file has ASCII text" do before do new_tempfile.write(plain_ascii) new_tempfile.close end it "calling for_output should return a valid diff" do differ.for_output.join("\\n").should match(/\A--- .*\\n\+\+\+ .*\\n@@/m) end it "calling for_reporting should return a utf-8 string" do expect(differ.for_reporting.encoding).to equal(Encoding::UTF_8) end end describe "when a file has UTF-8 text" do before do new_tempfile.write(utf_8) new_tempfile.close end it "calling for_output should complain that the content is binary" do expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ]) end it "calling for_reporting should be nil" do expect(differ.for_reporting).to be_nil end end describe "when a file has Latin-1 text" do before do new_tempfile.write(latin_1) new_tempfile.close end it "calling for_output should complain that the content is binary" do expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ]) end it "calling for_reporting should be nil" do expect(differ.for_reporting).to be_nil end end describe "when a file has Shift-JIS text" do before do new_tempfile.write(shift_jis) new_tempfile.close end it "calling for_output should return a valid diff" do differ.for_output.join("\\n").should match(/\A--- .*\\n\+\+\+ .*\\n@@/m) end it "calling for_reporting should return a utf-8 string" do expect(differ.for_reporting.encoding).to equal(Encoding::UTF_8) end end end describe "when testing the diff_filesize_threshold" do before do @diff_filesize_threshold_saved = Chef::Config[:diff_filesize_threshold] Chef::Config[:diff_filesize_threshold] = 10 end after do Chef::Config[:diff_filesize_threshold] = @diff_filesize_threshold_saved end describe "when the old_file goes over the threshold" do before do old_tempfile.write("But thats what you get when Wu-Tang raised you") old_tempfile.close end it "calling for_output should return the error message" do expect(differ.for_output).to eql( [ "(file sizes exceed 10 bytes, diff output suppressed)" ]) end it "calling for_reporting should be nil" do expect(differ.for_reporting).to be_nil end end describe "when the new_file goes over the threshold" do before do new_tempfile.write("But thats what you get when Wu-Tang raised you") new_tempfile.close end it "calling for_output should return the error message" do expect(differ.for_output).to eql( [ "(file sizes exceed 10 bytes, diff output suppressed)" ]) end it "calling for_reporting should be nil" do expect(differ.for_reporting).to be_nil end end end describe "when generating a valid diff" do before do old_tempfile.write("foo") old_tempfile.close new_tempfile.write("bar") new_tempfile.close end it "calling for_output should return a unified diff" do differ.for_output.size.should eql(5) differ.for_output.join("\\n").should match(/\A--- .*\\n\+\+\+ .*\\n@@/m) end it "calling for_reporting should return a unified diff" do differ.for_reporting.should match(/\A--- .*\\n\+\+\+ .*\\n@@/m) end describe "when the diff output is too long" do before do @diff_output_threshold_saved = Chef::Config[:diff_output_threshold] Chef::Config[:diff_output_threshold] = 10 end after do Chef::Config[:diff_output_threshold] = @diff_output_threshold_saved end it "calling for_output should return the error message" do expect(differ.for_output).to eql(["(long diff of over 10 characters, diff output suppressed)"]) end it "calling for_reporting should be nil" do expect(differ.for_reporting).to be_nil end end end describe "when checking if files are binary or text" do it "should identify zero-length files as text" do Tempfile.open("chef-util-diff-spec") do |file| file.close differ.send(:is_binary?, file.path).should be_false end end it "should identify text files as text" do Tempfile.open("chef-util-diff-spec") do |file| file.write(plain_ascii) file.close differ.send(:is_binary?, file.path).should be_false end end it "should identify a null-terminated string files as binary" do Tempfile.open("chef-util-diff-spec") do |file| file.write("This is a binary file.\0") file.close differ.send(:is_binary?, file.path).should be_true end end it "should identify null-teriminated multi-line string files as binary" do Tempfile.open("chef-util-diff-spec") do |file| file.write("This is a binary file.\nNo Really\nit is\0") file.close differ.send(:is_binary?, file.path).should be_true end end describe "when the default external encoding is UTF-8", :ruby_gte_19_only do before do @saved_default_external = Encoding.default_external Encoding.default_external = Encoding::UTF_8 end after do Encoding.default_external = @saved_default_external end it "should identify normal ASCII as text" do Tempfile.open("chef-util-diff-spec") do |file| file.write(plain_ascii) file.close differ.send(:is_binary?, file.path).should be_false end end it "should identify UTF-8 as text" do Tempfile.open("chef-util-diff-spec") do |file| file.write(utf_8) file.close differ.send(:is_binary?, file.path).should be_false end end it "should identify Latin-1 that is invalid UTF-8 as binary" do Tempfile.open("chef-util-diff-spec") do |file| file.write(latin_1) file.close differ.send(:is_binary?, file.path).should be_true end end it "should identify Shift-JIS that is invalid UTF-8 as binary" do Tempfile.open("chef-util-diff-spec") do |file| file.write(shift_jis) file.close differ.send(:is_binary?, file.path).should be_true end end end describe "when the default external encoding is Latin-1", :ruby_gte_19_only do before do @saved_default_external = Encoding.default_external Encoding.default_external = Encoding::ISO_8859_1 end after do Encoding.default_external = @saved_default_external end it "should identify normal ASCII as text" do Tempfile.open("chef-util-diff-spec") do |file| file.write(plain_ascii) file.close differ.send(:is_binary?, file.path).should be_false end end it "should identify UTF-8 that is invalid Latin-1 as binary" do Tempfile.open("chef-util-diff-spec") do |file| file.write(utf_8) file.close differ.send(:is_binary?, file.path).should be_true end end it "should identify Latin-1 as text" do Tempfile.open("chef-util-diff-spec") do |file| file.write(latin_1) file.close differ.send(:is_binary?, file.path).should be_false end end it "should identify Shift-JIS that is invalid Latin-1 as binary" do Tempfile.open("chef-util-diff-spec") do |file| file.write(shift_jis) file.close differ.send(:is_binary?, file.path).should be_true end end end describe "when the default external encoding is Shift-JIS", :ruby_gte_19_only do before do @saved_default_external = Encoding.default_external Encoding.default_external = Encoding::Shift_JIS end after do Encoding.default_external = @saved_default_external end it "should identify normal ASCII as text" do Tempfile.open("chef-util-diff-spec") do |file| file.write(plain_ascii) file.close differ.send(:is_binary?, file.path).should be_false end end it "should identify UTF-8 that is invalid Shift-JIS as binary" do Tempfile.open("chef-util-diff-spec") do |file| file.write(utf_8) file.close differ.send(:is_binary?, file.path).should be_true end end it "should identify Latin-1 that is invalid Shift-JIS as binary" do Tempfile.open("chef-util-diff-spec") do |file| file.write(latin_1) file.close differ.send(:is_binary?, file.path).should be_true end end it "should identify Shift-JIS as text" do Tempfile.open("chef-util-diff-spec") do |file| file.write(shift_jis) file.close differ.send(:is_binary?, file.path).should be_false end end end end end describe Chef::Util::Diff, :uses_diff => true do let!(:old_file) { old_tempfile.path } let!(:new_file) { new_tempfile.path } let(:plain_ascii) { "This is a text file.\nWith more than one line.\nAnd a \tTab.\nAnd lets make sure that other printable chars work too: ~!@\#$%^&*()`:\"<>?{}|_+,./;'[]\\-=\n" } # these are all byte sequences that are illegal in the other encodings... (but they may legally transcode) let(:utf_8) { "testing utf-8 unicode...\n\n\non a new line: \xE2\x80\x93\n" } # unicode em-dash let(:latin_1) { "It is more metal.\nif you have an \xFDmlaut.\n" } # NB: changed to y-with-diaresis, but i'm American so I don't know the difference let(:shift_jis) { "I have no idea what this character is:\n \x83\x80.\n" } # seriously, no clue, but \x80 is nice and illegal in other encodings let(:differ) do # subject differ = Chef::Util::Diff.new differ.diff(old_file, new_file) differ end describe "when file path has spaces" do include_context "using file paths with spaces" it_behaves_like "a diff util" end describe "when file path doesn't have spaces" do include_context "using file paths without spaces" it_behaves_like "a diff util" end end chef-11.8.2/spec/unit/util/file_edit_spec.rb0000644000004100000410000001052312254362222020712 0ustar www-datawww-data# # Author:: Nuo Yan () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Util::FileEdit do before(:each) do @hosts_content=<<-HOSTS 127.0.0.1 localhost 255.255.255.255 broadcasthost ::1 localhost fe80::1%lo0 localhost HOSTS @tempfile = Tempfile.open('file_edit_spec') @tempfile.write(@hosts_content) @tempfile.close @fedit = Chef::Util::FileEdit.new(@tempfile.path) end after(:each) do @tempfile && @tempfile.close! end describe "initialiize" do it "should create a new Chef::Util::FileEdit object" do Chef::Util::FileEdit.new(@tempfile.path).should be_kind_of(Chef::Util::FileEdit) end it "should throw an exception if the input file does not exist" do lambda{Chef::Util::FileEdit.new("nonexistfile")}.should raise_error end it "should throw an exception if the input file is blank" do lambda do Chef::Util::FileEdit.new(File.join(CHEF_SPEC_DATA, "filedit", "blank")) end.should raise_error end end describe "search_file_replace" do it "should accept regex passed in as a string (not Regexp object) and replace the match if there is one" do @fedit.search_file_replace("localhost", "replacement") @fedit.write_file newfile = File.new(@tempfile.path).readlines newfile[0].should match(/replacement/) end it "should accept regex passed in as a Regexp object and replace the match if there is one" do @fedit.search_file_replace(/localhost/, "replacement") @fedit.write_file newfile = File.new(@tempfile.path).readlines newfile[0].should match(/replacement/) end it "should do nothing if there isn't a match" do @fedit.search_file_replace(/pattern/, "replacement") @fedit.write_file newfile = File.new(@tempfile.path).readlines newfile[0].should_not match(/replacement/) end end describe "search_file_replace_line" do it "should search for match and replace the whole line" do @fedit.search_file_replace_line(/localhost/, "replacement line") @fedit.write_file newfile = File.new(@tempfile.path).readlines newfile[0].should match(/replacement/) newfile[0].should_not match(/127/) end end describe "search_file_delete" do it "should search for match and delete the match" do @fedit.search_file_delete(/localhost/) @fedit.write_file newfile = File.new(@tempfile.path).readlines newfile[0].should_not match(/localhost/) newfile[0].should match(/127/) end end describe "search_file_delete_line" do it "should search for match and delete the matching line" do @fedit.search_file_delete_line(/localhost/) @fedit.write_file newfile = File.new(@tempfile.path).readlines newfile[0].should_not match(/localhost/) newfile[0].should match(/broadcasthost/) end end describe "insert_line_after_match" do it "should search for match and insert the given line after the matching line" do @fedit.insert_line_after_match(/localhost/, "new line inserted") @fedit.write_file newfile = File.new(@tempfile.path).readlines newfile[1].should match(/new/) end end describe "insert_line_if_no_match" do it "should search for match and insert the given line if no line match" do @fedit.insert_line_if_no_match(/pattern/, "new line inserted") @fedit.write_file newfile = File.new(@tempfile.path).readlines newfile.last.should match(/new/) end it "should do nothing if there is a match" do @fedit.insert_line_if_no_match(/localhost/, "replacement") @fedit.write_file newfile = File.new(@tempfile.path).readlines newfile[1].should_not match(/replacement/) end end end chef-11.8.2/spec/unit/util/selinux_spec.rb0000644000004100000410000001313612254362222020460 0ustar www-datawww-data# # Author:: Serdar Sutay () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Util::Selinux do class TestClass include Chef::Util::Selinux def self.reset_state @@selinux_enabled = nil @@restorecon_path = nil @@selinuxenabled_path = nil end end before do TestClass.reset_state @test_instance = TestClass.new end after(:each) do TestClass.reset_state end it "each part of ENV['PATH'] should be checked" do expected_paths = ENV['PATH'].split(File::PATH_SEPARATOR) + [ '/bin', '/usr/bin', '/sbin', '/usr/sbin' ] expected_paths.each do |bin_path| selinux_path = File.join(bin_path, "selinuxenabled") File.should_receive(:executable?).with(selinux_path).and_return(false) end @test_instance.selinux_enabled?.should be_false end describe "when selinuxenabled binary exists" do before do @selinux_enabled_path = File.join("/sbin", "selinuxenabled") File.stub!(:executable?) do |file_path| file_path.end_with?("selinuxenabled").should be_true file_path == @selinux_enabled_path end end describe "when selinux is enabled" do before do cmd_result = mock("Cmd Result", :exitstatus => 0) @test_instance.should_receive(:shell_out!).once.with(@selinux_enabled_path, {:returns=>[0, 1]}).and_return(cmd_result) end it "should report selinux is enabled" do @test_instance.selinux_enabled?.should be_true # should check the file system only once for multiple calls @test_instance.selinux_enabled?.should be_true end end describe "when selinux is disabled" do before do cmd_result = mock("Cmd Result", :exitstatus => 1) @test_instance.should_receive(:shell_out!).once.with(@selinux_enabled_path, {:returns=>[0, 1]}).and_return(cmd_result) end it "should report selinux is disabled" do @test_instance.selinux_enabled?.should be_false # should check the file system only once for multiple calls @test_instance.selinux_enabled?.should be_false end end describe "when selinux gives an unexpected status" do before do cmd_result = mock("Cmd Result", :exitstatus => 101) @test_instance.should_receive(:shell_out!).once.with(@selinux_enabled_path, {:returns=>[0, 1]}).and_return(cmd_result) end it "should throw an error" do lambda {@test_instance.selinux_enabled?}.should raise_error(RuntimeError) end end end describe "when selinuxenabled binary doesn't exist" do before do File.stub!(:executable?) do |file_path| file_path.end_with?("selinuxenabled").should be_true false end end it "should report selinux is disabled" do @test_instance.selinux_enabled?.should be_false # should check the file system only once for multiple calls File.should_not_receive(:executable?) @test_instance.selinux_enabled?.should be_false end end describe "when restorecon binary exists on the system" do let (:path) { "/path/to/awesome" } before do @restorecon_enabled_path = File.join("/sbin", "restorecon") File.stub!(:executable?) do |file_path| file_path.end_with?("restorecon").should be_true file_path == @restorecon_enabled_path end end it "should call restorecon non-recursive by default" do restorecon_command = "#{@restorecon_enabled_path} -R #{path}" @test_instance.should_receive(:shell_out!).twice.with(restorecon_command) @test_instance.restore_security_context(path) File.should_not_receive(:executable?) @test_instance.restore_security_context(path) end it "should call restorecon recursive when recursive is set" do restorecon_command = "#{@restorecon_enabled_path} -R -r #{path}" @test_instance.should_receive(:shell_out!).twice.with(restorecon_command) @test_instance.restore_security_context(path, true) File.should_not_receive(:executable?) @test_instance.restore_security_context(path, true) end it "should call restorecon non-recursive when recursive is not set" do restorecon_command = "#{@restorecon_enabled_path} -R #{path}" @test_instance.should_receive(:shell_out!).twice.with(restorecon_command) @test_instance.restore_security_context(path) File.should_not_receive(:executable?) @test_instance.restore_security_context(path) end describe "when restorecon doesn't exist on the system" do before do File.stub!(:executable?) do |file_path| file_path.end_with?("restorecon").should be_true false end end it "should log a warning message" do log = [ ] Chef::Log.stub(:warn) do |message| log << message end @test_instance.restore_security_context(path) log.should_not be_empty File.should_not_receive(:executable?) @test_instance.restore_security_context(path) end end end end chef-11.8.2/spec/unit/util/backup_spec.rb0000644000004100000410000001164712254362222020243 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'tmpdir' describe Chef::Util::Backup do let (:tempfile) do Tempfile.new("chef-util-backup-spec-test") end before(:each) do @new_resource = mock("new_resource") @new_resource.should_receive(:path).at_least(:once).and_return(tempfile.path) @backup = Chef::Util::Backup.new(@new_resource) end it "should store the resource passed to new as new_resource" do @backup.new_resource.should eql(@new_resource) end describe "for cases when we don't want to back anything up" do before(:each) do @backup.should_not_receive(:do_backup) end it "should not attempt to backup a file if :backup is false" do @new_resource.should_receive(:backup).at_least(:once).and_return(false) @backup.backup! end it "should not attempt to backup a file if :backup == 0" do @new_resource.should_receive(:backup).at_least(:once).and_return(0) @backup.backup! end it "should not attempt to backup a file if it does not exist" do @new_resource.should_receive(:backup).at_least(:once).and_return(1) File.should_receive(:exist?).with(tempfile.path).at_least(:once).and_return(false) @backup.backup! end end describe "for cases when we want to back things up" do before(:each) do @backup.should_receive(:do_backup) end describe "when the number of backups is specified as 1" do before(:each) do @new_resource.should_receive(:backup).at_least(:once).and_return(1) end it "should not delete anything if this is the only backup" do @backup.should_receive(:sorted_backup_files).and_return(['a']) @backup.should_not_receive(:delete_backup) @backup.backup! end it "should keep only 1 backup copy" do @backup.should_receive(:sorted_backup_files).and_return(['a', 'b', 'c']) @backup.should_receive(:delete_backup).with('b') @backup.should_receive(:delete_backup).with('c') @backup.backup! end end describe "when the number of backups is specified as 2" do before(:each) do @new_resource.should_receive(:backup).at_least(:once).and_return(2) end it "should not delete anything if we only have one other backup" do @backup.should_receive(:sorted_backup_files).and_return(['a', 'b']) @backup.should_not_receive(:delete_backup) @backup.backup! end it "should keep only 2 backup copies" do @backup.should_receive(:sorted_backup_files).and_return(['a', 'b', 'c', 'd']) @backup.should_receive(:delete_backup).with('c') @backup.should_receive(:delete_backup).with('d') @backup.backup! end end end describe "backup_filename" do it "should return a timestamped path" do @backup.should_receive(:path).and_return('/a/b/c.txt') @backup.send(:backup_filename).should =~ %r|^/a/b/c.txt.chef-\d{14}.\d{6}$| end it "should strip the drive letter off for windows" do @backup.should_receive(:path).and_return('c:\a\b\c.txt') @backup.send(:backup_filename).should =~ %r|^\\a\\b\\c.txt.chef-\d{14}.\d{6}$| end it "should strip the drive letter off for windows (with forwardslashes)" do @backup.should_receive(:path).and_return('c:/a/b/c.txt') @backup.send(:backup_filename).should =~ %r|^/a/b/c.txt.chef-\d{14}.\d{6}$| end end describe "backup_path" do it "uses the file's directory when Chef::Config[:file_backup_path] is nil" do @backup.should_receive(:path).and_return('/a/b/c.txt') Chef::Config[:file_backup_path] = nil @backup.send(:backup_path).should =~ %r|^/a/b/c.txt.chef-\d{14}.\d{6}$| end it "uses the configured Chef::Config[:file_backup_path]" do @backup.should_receive(:path).and_return('/a/b/c.txt') Chef::Config[:file_backup_path] = '/backupdir' @backup.send(:backup_path).should =~ %r|^/backupdir[\\/]+a/b/c.txt.chef-\d{14}.\d{6}$| end it "uses the configured Chef::Config[:file_backup_path] and strips the drive on windows" do @backup.should_receive(:path).and_return('c:\\a\\b\\c.txt') Chef::Config[:file_backup_path] = 'c:\backupdir' @backup.send(:backup_path).should =~ %r|^c:\\backupdir[\\/]+a\\b\\c.txt.chef-\d{14}.\d{6}$| end end end chef-11.8.2/spec/unit/provider_spec.rb0000644000004100000410000001222212254362222017641 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' class NoWhyrunDemonstrator < Chef::Provider attr_reader :system_state_altered def whyrun_supported? false end def load_current_resource end def action_foo @system_state_altered = true end end class ConvergeActionDemonstrator < Chef::Provider attr_reader :system_state_altered def whyrun_supported? true end def load_current_resource end def action_foo converge_by("running a state changing action") do @system_state_altered = true end end end describe Chef::Provider do before(:each) do @cookbook_collection = Chef::CookbookCollection.new([]) @node = Chef::Node.new @node.name "latte" @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) @resource = Chef::Resource.new("funk", @run_context) @resource.cookbook_name = "a_delicious_pie" @provider = Chef::Provider.new(@resource, @run_context) end it "should store the resource passed to new as new_resource" do @provider.new_resource.should eql(@resource) end it "should store the node passed to new as node" do @provider.node.should eql(@node) end it "should have nil for current_resource by default" do @provider.current_resource.should eql(nil) end it "should not support whyrun by default" do @provider.send(:whyrun_supported?).should eql(false) end it "should return true for action_nothing" do @provider.action_nothing.should eql(true) end it "evals embedded recipes with a pristine resource collection" do @provider.run_context.instance_variable_set(:@resource_collection, "doesn't matter what this is") temporary_collection = nil snitch = Proc.new {temporary_collection = @run_context.resource_collection} @provider.send(:recipe_eval, &snitch) temporary_collection.should be_an_instance_of(Chef::ResourceCollection) @provider.run_context.instance_variable_get(:@resource_collection).should == "doesn't matter what this is" end it "does not re-load recipes when creating the temporary run context" do # we actually want to test that RunContext#load is never called, but we # can't stub all instances of an object with rspec's mocks. :/ Chef::RunContext.stub!(:new).and_raise("not supposed to happen") snitch = Proc.new {temporary_collection = @run_context.resource_collection} @provider.send(:recipe_eval, &snitch) end context "when no converge actions are queued" do before do @provider.stub!(:whyrun_supported?).and_return(true) @provider.stub!(:load_current_resource) end it "does not mark the new resource as updated" do @resource.should_not be_updated @resource.should_not be_updated_by_last_action end end context "when converge actions have been added to the queue" do describe "and provider supports whyrun mode" do before do @provider = ConvergeActionDemonstrator.new(@resource, @run_context) end it "should tell us that it does support whyrun" do @provider.should be_whyrun_supported end it "queues up converge actions" do @provider.action_foo @provider.send(:converge_actions).should have(1).actions end it "executes pending converge actions to converge the system" do @provider.run_action(:foo) @provider.instance_variable_get(:@system_state_altered).should be_true end it "marks the resource as updated" do @provider.run_action(:foo) @resource.should be_updated @resource.should be_updated_by_last_action end end describe "and provider does not support whyrun mode" do before do Chef::Config[:why_run] = true @provider = NoWhyrunDemonstrator.new(@resource, @run_context) end after do Chef::Config[:why_run] = false end it "should tell us that it doesn't support whyrun" do @provider.should_not be_whyrun_supported end it "should automatically generate a converge_by block on the provider's behalf" do @provider.run_action(:foo) @provider.send(:converge_actions).should have(0).actions @provider.system_state_altered.should be_false end it "should automatically execute the generated converge_by block" do @provider.run_action(:foo) @provider.system_state_altered.should be_false @resource.should_not be_updated @resource.should_not be_updated_by_last_action end end end end chef-11.8.2/spec/unit/shell_spec.rb0000644000004100000410000001160312254362222017120 0ustar www-datawww-data# Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 Daniel DeLeo # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require "ostruct" ObjectTestHarness = Proc.new do extend Shell::Extensions::ObjectCoreExtensions def conf=(new_conf) @conf = new_conf end def conf @conf end desc "rspecin'" def rspec_method end end class TestJobManager attr_accessor :jobs end describe Shell do before do Shell.irb_conf = {} Shell::ShellSession.instance.rspec_reset Shell::ShellSession.instance.stub!(:reset!) end describe "reporting its status" do it "alway says it is running" do Shell.should be_running end end describe "configuring IRB" do it "configures irb history" do Shell.configure_irb Shell.irb_conf[:HISTORY_FILE].should == "~/.chef/chef_shell_history" Shell.irb_conf[:SAVE_HISTORY].should == 1000 end it "has a prompt like ``chef > '' in the default context" do Shell.configure_irb conf = OpenStruct.new conf.main = Object.new conf.main.instance_eval(&ObjectTestHarness) Shell.irb_conf[:IRB_RC].call(conf) conf.prompt_c.should == "chef > " conf.return_format.should == " => %s \n" conf.prompt_i.should == "chef > " conf.prompt_n.should == "chef ?> " conf.prompt_s.should == "chef%l> " end it "has a prompt like ``chef:recipe > '' in recipe context" do Shell.configure_irb conf = OpenStruct.new events = Chef::EventDispatch::Dispatcher.new conf.main = Chef::Recipe.new(nil,nil,Chef::RunContext.new(Chef::Node.new, {}, events)) Shell.irb_conf[:IRB_RC].call(conf) conf.prompt_c.should == "chef:recipe > " conf.prompt_i.should == "chef:recipe > " conf.prompt_n.should == "chef:recipe ?> " conf.prompt_s.should == "chef:recipe%l> " end it "has a prompt like ``chef:attributes > '' in attributes/node context" do Shell.configure_irb conf = OpenStruct.new conf.main = Chef::Node.new Shell.irb_conf[:IRB_RC].call(conf) conf.prompt_c.should == "chef:attributes > " conf.prompt_i.should == "chef:attributes > " conf.prompt_n.should == "chef:attributes ?> " conf.prompt_s.should == "chef:attributes%l> " end end describe "convenience macros for creating the chef object" do before do @chef_object = Object.new @chef_object.instance_eval(&ObjectTestHarness) end it "creates help text for methods with descriptions" do @chef_object.help_descriptions.should == [Shell::Extensions::Help.new("rspec_method", "rspecin'", nil)] end it "adds help text when a new method is described then defined" do describe_define =<<-EVAL desc "foo2the Bar" def baz end EVAL @chef_object.instance_eval describe_define @chef_object.help_descriptions.should == [Shell::Extensions::Help.new("rspec_method", "rspecin'"), Shell::Extensions::Help.new("baz", "foo2the Bar")] end it "adds help text for subcommands" do describe_define =<<-EVAL subcommands :baz_obj_command => "something you can do with baz.baz_obj_command" def baz end EVAL @chef_object.instance_eval describe_define expected_help_text_fragments = [Shell::Extensions::Help.new("rspec_method", "rspecin'")] expected_help_text_fragments << Shell::Extensions::Help.new("baz.baz_obj_command", "something you can do with baz.baz_obj_command") @chef_object.help_descriptions.should == expected_help_text_fragments end it "doesn't add previous subcommand help to commands defined afterward" do describe_define =<<-EVAL desc "swingFromTree" def monkey_time end def super_monkey_time end EVAL @chef_object.instance_eval describe_define @chef_object.help_descriptions.should have(2).descriptions @chef_object.help_descriptions.select {|h| h.cmd == "super_monkey_time" }.should be_empty end it "creates a help banner with the command descriptions" do @chef_object.help_banner.should match(/^\|\ Command[\s]+\|\ Description[\s]*$/) @chef_object.help_banner.should match(/^\|\ rspec_method[\s]+\|\ rspecin\'[\s]*$/) end end end chef-11.8.2/spec/unit/api_client/0000755000004100000410000000000012254362222016560 5ustar www-datawww-datachef-11.8.2/spec/unit/api_client/registration_spec.rb0000644000004100000410000001454412254362222022641 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'tempfile' require 'chef/api_client/registration' describe Chef::ApiClient::Registration do let(:key_location) do make_tmpname("client-registration-key") end let(:registration) { Chef::ApiClient::Registration.new("silent-bob", key_location) } let :private_key_data do File.open(Chef::Config[:validation_key], "r") {|f| f.read.chomp } end before do Chef::Config[:validation_client_name] = "test-validator" Chef::Config[:validation_key] = File.expand_path('ssl/private_key.pem', CHEF_SPEC_DATA) end after do File.unlink(key_location) if File.exist?(key_location) Chef::Config[:validation_client_name] = nil Chef::Config[:validation_key] = nil end it "has an HTTP client configured with validator credentials" do registration.http_api.should be_a_kind_of(Chef::REST) registration.http_api.client_name.should == "test-validator" registration.http_api.signing_key.should == private_key_data end describe "when creating/updating the client on the server" do let(:http_mock) { mock("Chef::REST mock") } before do registration.stub!(:http_api).and_return(http_mock) end it "creates a new ApiClient on the server using the validator identity" do response = {"uri" => "https://chef.local/clients/silent-bob", "private_key" => "--begin rsa key etc--"} http_mock.should_receive(:post). with("clients", :name => 'silent-bob', :admin => false). and_return(response) registration.create_or_update.should == response registration.private_key.should == "--begin rsa key etc--" end context "and the client already exists on a Chef 10 server" do it "requests a new key from the server and saves it" do response = {"name" => "silent-bob", "private_key" => "--begin rsa key etc--" } response_409 = Net::HTTPConflict.new("1.1", "409", "Conflict") exception_409 = Net::HTTPServerException.new("409 conflict", response_409) http_mock.should_receive(:post).and_raise(exception_409) http_mock.should_receive(:put). with("clients/silent-bob", :name => 'silent-bob', :admin => false, :private_key => true). and_return(response) registration.create_or_update.should == response registration.private_key.should == "--begin rsa key etc--" end end context "and the client already exists on a Chef 11 server" do it "requests a new key from the server and saves it" do response = Chef::ApiClient.new response.name("silent-bob") response.private_key("--begin rsa key etc--") response_409 = Net::HTTPConflict.new("1.1", "409", "Conflict") exception_409 = Net::HTTPServerException.new("409 conflict", response_409) http_mock.should_receive(:post).and_raise(exception_409) http_mock.should_receive(:put). with("clients/silent-bob", :name => 'silent-bob', :admin => false, :private_key => true). and_return(response) registration.create_or_update.should == response registration.private_key.should == "--begin rsa key etc--" end end end describe "when writing the private key to disk" do before do registration.stub!(:private_key).and_return('--begin rsa key etc--') end # Permission read via File.stat is busted on windows, though creating the # file with 0600 has the desired effect of giving access rights to the # owner only. A platform-specific functional test would be helpful. it "creates the file with 0600 permissions", :unix_only do File.should_not exist(key_location) registration.write_key File.should exist(key_location) stat = File.stat(key_location) (stat.mode & 07777).should == 0600 end it "writes the private key content to the file" do registration.write_key IO.read(key_location).should == "--begin rsa key etc--" end end describe "when registering a client" do let(:http_mock) { mock("Chef::REST mock") } before do registration.stub!(:http_api).and_return(http_mock) end it "creates the client on the server and writes the key" do response = {"uri" => "http://chef.local/clients/silent-bob", "private_key" => "--begin rsa key etc--" } http_mock.should_receive(:post).ordered.and_return(response) registration.run IO.read(key_location).should == "--begin rsa key etc--" end it "retries up to 5 times" do response_500 = Net::HTTPInternalServerError.new("1.1", "500", "Internal Server Error") exception_500 = Net::HTTPFatalError.new("500 Internal Server Error", response_500) http_mock.should_receive(:post).ordered.and_raise(exception_500) # 1 http_mock.should_receive(:post).ordered.and_raise(exception_500) # 2 http_mock.should_receive(:post).ordered.and_raise(exception_500) # 3 http_mock.should_receive(:post).ordered.and_raise(exception_500) # 4 http_mock.should_receive(:post).ordered.and_raise(exception_500) # 5 response = {"uri" => "http://chef.local/clients/silent-bob", "private_key" => "--begin rsa key etc--" } http_mock.should_receive(:post).ordered.and_return(response) registration.run IO.read(key_location).should == "--begin rsa key etc--" end it "gives up retrying after the max attempts" do response_500 = Net::HTTPInternalServerError.new("1.1", "500", "Internal Server Error") exception_500 = Net::HTTPFatalError.new("500 Internal Server Error", response_500) http_mock.should_receive(:post).exactly(6).times.and_raise(exception_500) lambda {registration.run}.should raise_error(Net::HTTPFatalError) end end end chef-11.8.2/spec/unit/scan_access_control_spec.rb0000644000004100000410000001311512254362222022016 0ustar www-datawww-data# Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, inc. # License:: Apache License, Version 2.0 # # 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. # require File.expand_path("../../spec_helper", __FILE__) require 'chef/scan_access_control' describe Chef::ScanAccessControl do before do @new_resource = Chef::Resource::File.new("/tmp/foo/bar/baz/link") @real_file = "/tmp/foo/bar/real/file" @current_resource = Chef::Resource::File.new(@new_resource.path) @scanner = Chef::ScanAccessControl.new(@new_resource, @current_resource) end describe "when the fs entity does not exist" do before do @new_resource.tap do |f| f.owner("root") f.group("root") f.mode('0755') end @scanner.set_all! end it "does not set any fields on the current resource" do @current_resource.owner.should be_nil @current_resource.group.should be_nil @current_resource.mode.should be_nil end end describe "when the fs entity exists" do before do @stat = mock("File::Stat for #{@new_resource.path}", :uid => 0, :gid => 0, :mode => 00100644) File.should_receive(:realpath).with(@new_resource.path).and_return(@real_file) File.should_receive(:stat).with(@real_file).and_return(@stat) File.should_receive(:exist?).with(@new_resource.path).and_return(true) end describe "when new_resource does not specify mode, user or group" do # these tests are necessary for minitest-chef-handler to use as an API, see CHEF-3235 before do @scanner.set_all! end it "sets the mode of the current resource to the current mode as a String" do @current_resource.mode.should == "0644" end context "on unix", :unix_only do it "sets the group of the current resource to the current group as a String" do @current_resource.group.should == Etc.getgrgid(0).name end it "sets the owner of the current resource to the current owner as a String" do @current_resource.user.should == "root" end end context "on windows", :windows_only do it "sets the group of the current resource to the current group as a String" do @current_resource.group.should == 0 end it "sets the owner of the current resource to the current owner as a String" do @current_resource.user.should == 0 end end end describe "when new_resource specifies the mode with a string" do before do @new_resource.mode("0755") @scanner.set_all! end it "sets the mode of the current resource to the file's current mode as a string" do @current_resource.mode.should == "0644" end end describe "when new_resource specified the mode with an integer" do before do @new_resource.mode(00755) @scanner.set_all! end it "sets the mode of the current resource to the current mode as a String" do @current_resource.mode.should == "0644" end end describe "when new_resource specifies the user with a UID" do before do @new_resource.user(0) @scanner.set_all! end it "sets the owner of current_resource to the UID of the current owner" do @current_resource.user.should == 0 end end describe "when new_resource specifies the user with a username" do before do @new_resource.user("root") end it "sets the owner of current_resource to the username of the current owner" do @root_passwd = mock("Struct::Passwd for uid 0", :name => "root") Etc.should_receive(:getpwuid).with(0).and_return(@root_passwd) @scanner.set_all! @current_resource.user.should == "root" end describe "and there is no passwd entry for the user" do it "sets the owner of the current_resource to the UID" do Etc.should_receive(:getpwuid).with(0).and_raise(ArgumentError) @scanner.set_all! @current_resource.user.should == 0 end end end describe "when new_resource specifies the group with a GID" do before do @new_resource.group(0) @scanner.set_all! end it "sets the group of the current_resource to the gid of the current owner" do @current_resource.group.should == 0 end end describe "when new_resource specifies the group with a group name" do before do @new_resource.group("wheel") end it "sets the group of the current resource to the group name" do @group_entry = mock("Struct::Group for wheel", :name => "wheel") Etc.should_receive(:getgrgid).with(0).and_return(@group_entry) @scanner.set_all! @current_resource.group.should == "wheel" end describe "and there is no group entry for the group" do it "sets the current_resource's group to the GID" do Etc.should_receive(:getgrgid).with(0).and_raise(ArgumentError) @scanner.set_all! @current_resource.group.should == 0 end end end end end chef-11.8.2/spec/unit/run_list/0000755000004100000410000000000012254362222016310 5ustar www-datawww-datachef-11.8.2/spec/unit/run_list/run_list_item_spec.rb0000644000004100000410000001026312254362222022526 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::RunList::RunListItem do describe "when creating from a Hash" do it "raises an exception when the hash doesn't have a :type key" do lambda {Chef::RunList::RunListItem.new(:name => "tatft")}.should raise_error(ArgumentError) end it "raises an exception when the hash doesn't have an :name key" do lambda {Chef::RunList::RunListItem.new(:type => 'R') }.should raise_error(ArgumentError) end it "sets the name and type as given in the hash" do item = Chef::RunList::RunListItem.new(:type => 'fuuu', :name => 'uuuu') item.to_s.should == 'fuuu[uuuu]' end end describe "when creating an item from a string" do it "parses a qualified recipe" do item = Chef::RunList::RunListItem.new("recipe[rage]") item.should be_a_recipe item.should_not be_a_role item.to_s.should == 'recipe[rage]' item.name.should == 'rage' end it "parses a qualified recipe with a version" do item = Chef::RunList::RunListItem.new("recipe[rage@0.1.0]") item.should be_a_recipe item.should_not be_a_role item.to_s.should == 'recipe[rage@0.1.0]' item.name.should == 'rage' item.version.should == '0.1.0' end it "parses a qualified role" do item = Chef::RunList::RunListItem.new("role[fist]") item.should be_a_role item.should_not be_a_recipe item.to_s.should == 'role[fist]' item.name.should == 'fist' end it "parses an unqualified recipe" do item = Chef::RunList::RunListItem.new("lobster") item.should be_a_recipe item.should_not be_a_role item.to_s.should == 'recipe[lobster]' item.name.should == 'lobster' end it "raises an exception when the string has typo on the type part" do lambda {Chef::RunList::RunListItem.new("Recipe[lobster]") }.should raise_error(ArgumentError) end it "raises an exception when the string has extra space between the type and the name" do lambda {Chef::RunList::RunListItem.new("recipe [lobster]") }.should raise_error(ArgumentError) end it "raises an exception when the string does not close the bracket" do lambda {Chef::RunList::RunListItem.new("recipe[lobster") }.should raise_error(ArgumentError) end end describe "comparing to other run list items" do it "is equal to another run list item that has the same name and type" do item1 = Chef::RunList::RunListItem.new('recipe[lrf]') item2 = Chef::RunList::RunListItem.new('recipe[lrf]') item1.should == item2 end it "is not equal to another run list item with the same name and different type" do item1 = Chef::RunList::RunListItem.new('recipe[lrf]') item2 = Chef::RunList::RunListItem.new('role[lrf]') item1.should_not == item2 end it "is not equal to another run list item with the same type and different name" do item1 = Chef::RunList::RunListItem.new('recipe[lrf]') item2 = Chef::RunList::RunListItem.new('recipe[lobsterragefist]') item1.should_not == item2 end it "is not equal to another run list item with the same name and type but different version" do item1 = Chef::RunList::RunListItem.new('recipe[lrf,0.1.0]') item2 = Chef::RunList::RunListItem.new('recipe[lrf,0.2.0]') item1.should_not == item2 end end describe "comparing to strings" do it "is equal to a string if that string matches its to_s representation" do Chef::RunList::RunListItem.new('recipe[lrf]').should == 'recipe[lrf]' end end end chef-11.8.2/spec/unit/run_list/run_list_expansion_spec.rb0000644000004100000410000000765712254362222023611 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::RunList::RunListExpansion do before do @run_list = Chef::RunList.new @run_list << 'recipe[lobster]' << 'role[rage]' << 'recipe[fist]' @expansion = Chef::RunList::RunListExpansion.new("_default", @run_list.run_list_items) end describe "before expanding the run list" do it "has an array of run list items" do @expansion.run_list_items.should == @run_list.run_list_items end it "has default_attrs" do @expansion.default_attrs.should == Mash.new end it "has override attrs" do @expansion.override_attrs.should == Mash.new end it "it has an empty list of recipes" do @expansion.should have(0).recipes end it "has not applied its roles" do @expansion.applied_role?('rage').should be_false end end describe "after applying a role with environment-specific run lists" do before do @rage_role = Chef::Role.new.tap do |r| r.name("rage") r.env_run_lists('_default' => [], "prod" => ["recipe[prod-only]"]) end @expansion = Chef::RunList::RunListExpansion.new("prod", @run_list.run_list_items) @expansion.should_receive(:fetch_role).and_return(@rage_role) @expansion.expand end it "has the correct list of recipes for the given environment" do @expansion.recipes.should == ["lobster", "prod-only", "fist"] end end describe "after applying a role" do before do @expansion.stub!(:fetch_role).and_return(Chef::Role.new) @expansion.inflate_role('rage', "role[base]") end it "tracks the applied role" do @expansion.applied_role?('rage').should be_true end it "does not inflate the role again" do @expansion.inflate_role('rage', "role[base]").should be_false end end describe "after expanding a run list" do before do @first_role = Chef::Role.new @first_role.run_list('role[mollusk]') @first_role.default_attributes({'foo' => 'bar'}) @first_role.override_attributes({'baz' => 'qux'}) @second_role = Chef::Role.new @second_role.run_list('recipe[crabrevenge]') @second_role.default_attributes({'foo' => 'boo'}) @second_role.override_attributes({'baz' => 'bux'}) @expansion.stub!(:fetch_role).and_return(@first_role, @second_role) @expansion.expand end it "has the ordered list of recipes" do @expansion.recipes.should == ['lobster', 'crabrevenge', 'fist'] end it "has the merged attributes from the roles with outer roles overridding inner" do @expansion.default_attrs.should == {'foo' => 'bar'} @expansion.override_attrs.should == {'baz' => 'qux'} end it "has the list of all roles applied" do # this is the correct order, but 1.8 hash order is not stable @expansion.roles.should =~ ['rage', 'mollusk'] end end describe "after expanding a run list with a non existant role" do before do @expansion.stub!(:fetch_role) { @expansion.role_not_found('crabrevenge', "role[base]") } @expansion.expand end it "is invalid" do @expansion.should be_invalid @expansion.errors?.should be_true # aliases end it "has a list of invalid role names" do @expansion.errors.should include('crabrevenge') end end end chef-11.8.2/spec/unit/run_list/versioned_recipe_list_spec.rb0000644000004100000410000000777312254362222024245 0ustar www-datawww-data# # Author:: Stephen Delano () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'spec_helper' describe Chef::RunList::VersionedRecipeList do describe "initialize" do it "should create an empty array" do l = Chef::RunList::VersionedRecipeList.new l.should == [] end end describe "add_recipe" do before(:each) do @list = Chef::RunList::VersionedRecipeList.new @list << "apt" @list << "god" @list << "apache2" end it "should append the recipe to the end of the list" do @list.add_recipe "rails" @list.should == ["apt", "god", "apache2", "rails"] end it "should not duplicate entries" do @list.add_recipe "apt" @list.should == ["apt", "god", "apache2"] end it "should allow you to specify a version" do @list.add_recipe "rails", "1.0.0" @list.should == ["apt", "god", "apache2", "rails"] @list.with_versions.should include({:name => "rails", :version => "1.0.0"}) end it "should allow you to specify a version for a recipe that already exists" do @list.add_recipe "apt", "1.2.3" @list.should == ["apt", "god", "apache2"] @list.with_versions.should include({:name => "apt", :version => "1.2.3"}) end it "should allow you to specify the same version of a recipe twice" do @list.add_recipe "rails", "1.0.0" @list.add_recipe "rails", "1.0.0" @list.with_versions.should include({:name => "rails", :version => "1.0.0"}) end it "should allow you to spcify no version, even when a version already exists" do @list.add_recipe "rails", "1.0.0" @list.add_recipe "rails" @list.with_versions.should include({:name => "rails", :version => "1.0.0"}) end it "should not allow multiple versions of the same recipe" do @list.add_recipe "rails", "1.0.0" lambda {@list.add_recipe "rails", "0.1.0"}.should raise_error Chef::Exceptions::CookbookVersionConflict end end describe "with_versions" do before(:each) do @recipes = [ {:name => "apt", :version => "1.0.0"}, {:name => "god", :version => nil}, {:name => "apache2", :version => "0.0.1"} ] @list = Chef::RunList::VersionedRecipeList.new @recipes.each {|i| @list.add_recipe i[:name], i[:version]} end it "should return an array of hashes with :name and :version" do @list.with_versions.should == @recipes end it "should retain the same order as the version-less list" do with_versions = @list.with_versions @list.each_with_index do |item, index| with_versions[index][:name].should == item end end end describe "with_version_constraints" do before(:each) do @recipes = [ {:name => "apt", :version => "~> 1.2.0"}, {:name => "god", :version => nil}, {:name => "apache2", :version => "0.0.1"} ] @list = Chef::RunList::VersionedRecipeList.new @recipes.each {|i| @list.add_recipe i[:name], i[:version]} @constraints = @recipes.map do |x| { :name => x[:name], :version_constraint => Chef::VersionConstraint.new(x[:version]) } end end it "should return an array of hashes with :name and :version_constraint" do @list.with_version_constraints.each do |x| x.should have_key :name x[:version_constraint].should_not be nil end end end end chef-11.8.2/spec/unit/version_constraint/0000755000004100000410000000000012254362222020402 5ustar www-datawww-datachef-11.8.2/spec/unit/version_constraint/platform_spec.rb0000644000004100000410000000267312254362222023575 0ustar www-datawww-data# Author:: Xabier de Zuazo () # Copyright:: Copyright (c) 2013 Onddo Labs, SL. # License:: Apache License, Version 2.0 # # 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. require 'spec_helper' require 'chef/version_constraint/platform' describe Chef::VersionConstraint::Platform do it "is a subclass of Chef::VersionConstraint" do v = Chef::VersionConstraint::Platform.new v.should be_an_instance_of(Chef::VersionConstraint::Platform) v.should be_a_kind_of(Chef::VersionConstraint) end it "should work with Chef::Version::Platform classes" do vc = Chef::VersionConstraint::Platform.new("1.0") vc.version.should be_an_instance_of(Chef::Version::Platform) end describe "include?" do it "pessimistic ~> x" do vc = Chef::VersionConstraint::Platform.new "~> 1" vc.should include "1.3.3" vc.should include "1.4" vc.should_not include "2.2" vc.should_not include "0.3.0" end end end chef-11.8.2/spec/unit/json_compat_spec.rb0000644000004100000410000001471412254362222020333 0ustar www-datawww-data# # Author:: Juanje Ojeda () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require File.expand_path('../../spec_helper', __FILE__) require 'chef/json_compat' describe Chef::JSONCompat do describe "with JSON containing an existing class" do let(:json){'{"json_class": "Chef::Role"}'} it "returns an instance of the class instead of a Hash" do Chef::JSONCompat.from_json(json).class.should eq Chef::Role end end describe 'with JSON containing "Chef::Sandbox" as a json_class value' do require 'chef/sandbox' # Only needed for this test let(:json){'{"json_class": "Chef::Sandbox", "arbitrary": "data"}'} it "returns a Hash, because Chef::Sandbox is a dummy class" do Chef::JSONCompat.from_json(json).should eq({"json_class" => "Chef::Sandbox", "arbitrary" => "data"}) end end describe "with a file with 300 or less nested entries" do before(:all) do @json = IO.read(File.join(CHEF_SPEC_DATA, 'big_json.json')) @hash = Chef::JSONCompat.from_json(@json) end describe "when a big json file is loaded" do it "should create a Hash from the file" do @hash.should be_kind_of(Hash) end it "should has 'test' as a 300th nested value" do @hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key'].should == 'test' end end end describe "with a file with more than 300 nested entries" do before(:all) do @json = IO.read(File.join(CHEF_SPEC_DATA, 'big_json_plus_one.json')) @hash = Chef::JSONCompat.from_json(@json, {:max_nesting => 301}) end describe "when a big json file is loaded" do it "should create a Hash from the file" do @hash.should be_kind_of(Hash) end it "should has 'test' as a 301st nested value" do @hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key'].should == 'test' end end end end chef-11.8.2/spec/unit/daemon_spec.rb0000644000004100000410000001225112254362222017254 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'spec_helper' require 'ostruct' describe Chef::Daemon do before do if windows? mock_struct = #Struct::Passwd.new(nil, nil, 111, 111) mock_struct = OpenStruct.new(:uid => 2342, :gid => 2342) Etc.stub!(:getpwnam).and_return mock_struct Etc.stub!(:getgrnam).and_return mock_struct # mock unimplemented methods Process.stub!(:initgroups).and_return nil Process::GID.stub!(:change_privilege).and_return 11 Process::UID.stub!(:change_privilege).and_return 11 end end describe ".pid_file" do describe "when the pid_file option has been set" do before do Chef::Config[:pid_file] = "/var/run/chef/chef-client.pid" end it "should return the supplied value" do Chef::Daemon.pid_file.should eql("/var/run/chef/chef-client.pid") end end describe "without the pid_file option set" do before do Chef::Daemon.name = "chef-client" end it "should return a valued based on @name" do Chef::Daemon.pid_file.should eql("/tmp/chef-client.pid") end end end describe ".pid_from_file" do before do Chef::Config[:pid_file] = "/var/run/chef/chef-client.pid" end it "should suck the pid out of pid_file" do File.should_receive(:read).with("/var/run/chef/chef-client.pid").and_return("1337") Chef::Daemon.pid_from_file end end describe ".change_privilege" do before do Chef::Application.stub!(:fatal!).and_return(true) Chef::Config[:user] = 'aj' Dir.stub!(:chdir) end it "changes the working directory to root" do Dir.rspec_reset Dir.should_receive(:chdir).with("/").and_return(0) Chef::Daemon.change_privilege end describe "when the user and group options are supplied" do before do Chef::Config[:group] = 'staff' end it "should log an appropriate info message" do Chef::Log.should_receive(:info).with("About to change privilege to aj:staff") Chef::Daemon.change_privilege end it "should call _change_privilege with the user and group" do Chef::Daemon.should_receive(:_change_privilege).with("aj", "staff") Chef::Daemon.change_privilege end end describe "when just the user option is supplied" do it "should log an appropriate info message" do Chef::Log.should_receive(:info).with("About to change privilege to aj") Chef::Daemon.change_privilege end it "should call _change_privilege with just the user" do Chef::Daemon.should_receive(:_change_privilege).with("aj") Chef::Daemon.change_privilege end end end describe "._change_privilege" do before do Process.stub!(:euid).and_return(0) Process.stub!(:egid).and_return(0) Process::UID.stub!(:change_privilege).and_return(nil) Process::GID.stub!(:change_privilege).and_return(nil) @pw_user = mock("Struct::Passwd", :uid => 501) @pw_group = mock("Struct::Group", :gid => 20) Process.stub!(:initgroups).and_return(true) Etc.stub!(:getpwnam).and_return(@pw_user) Etc.stub!(:getgrnam).and_return(@pw_group) end describe "with sufficient privileges" do before do Process.stub!(:euid).and_return(0) Process.stub!(:egid).and_return(0) end it "should initialize the supplemental group list" do Process.should_receive(:initgroups).with("aj", 20) Chef::Daemon._change_privilege("aj") end it "should attempt to change the process GID" do Process::GID.should_receive(:change_privilege).with(20).and_return(20) Chef::Daemon._change_privilege("aj") end it "should attempt to change the process UID" do Process::UID.should_receive(:change_privilege).with(501).and_return(501) Chef::Daemon._change_privilege("aj") end end describe "with insufficient privileges" do before do Process.stub!(:euid).and_return(999) Process.stub!(:egid).and_return(999) end it "should log an appropriate error message and fail miserably" do Process.stub!(:initgroups).and_raise(Errno::EPERM) error = "Operation not permitted" if RUBY_PLATFORM.match("solaris2") || RUBY_PLATFORM.match("aix") error = "Not owner" end Chef::Application.should_receive(:fatal!).with("Permission denied when trying to change 999:999 to 501:20. #{error}") Chef::Daemon._change_privilege("aj") end end end end chef-11.8.2/spec/unit/version/0000755000004100000410000000000012254362222016136 5ustar www-datawww-datachef-11.8.2/spec/unit/version/platform_spec.rb0000644000004100000410000000356112254362222021326 0ustar www-datawww-data# Author:: Xabier de Zuazo () # Copyright:: Copyright (c) 2013 Onddo Labs, SL. # License:: Apache License, Version 2.0 # # 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. require 'spec_helper' require 'chef/version/platform' describe Chef::Version::Platform do it "is a subclass of Chef::Version" do v = Chef::Version::Platform.new('1.1') v.should be_an_instance_of(Chef::Version::Platform) v.should be_a_kind_of(Chef::Version) end it "should transform 1 to 1.0.0" do Chef::Version::Platform.new("1").to_s.should == "1.0.0" end describe "when creating valid Versions" do good_versions = %w(1 1.2 1.2.3 1000.80.50000 0.300.25 001.02.00003) good_versions.each do |v| it "should accept '#{v}'" do Chef::Version::Platform.new v end end end describe "when given bogus input" do bad_versions = ["1.2.3.4", "1.2.a4", "a", "1.2 3", "1.2 a", "1 2 3", "1-2-3", "1_2_3", "1.2_3", "1.2-3"] the_error = Chef::Exceptions::InvalidPlatformVersion bad_versions.each do |v| it "should raise #{the_error} when given '#{v}'" do lambda { Chef::Version::Platform.new v }.should raise_error(the_error) end end end describe "<=>" do it "should equate versions 1 and 1.0.0" do Chef::Version::Platform.new("1").should == Chef::Version::Platform.new("1.0.0") end end end chef-11.8.2/spec/unit/checksum/0000755000004100000410000000000012254362222016253 5ustar www-datawww-datachef-11.8.2/spec/unit/checksum/storage/0000755000004100000410000000000012254362222017717 5ustar www-datawww-datachef-11.8.2/spec/unit/checksum/storage/filesystem_spec.rb0000644000004100000410000000472112254362222023446 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/checksum/storage/filesystem' describe Chef::Checksum::Storage::Filesystem do before do Chef::Log.logger = Logger.new(StringIO.new) @now = Time.now Time.stub!(:now).and_return(@now) Chef::Config.stub!(:checksum_path).and_return("/var/chef/checksums") @checksum_of_the_file = "3fafecfb15585ede6b840158cbc2f399" @storage = Chef::Checksum::Storage::Filesystem.new("/not/used/path", @checksum_of_the_file) end it "has the path to the file in the checksum repo" do @storage.file_location.should == "/var/chef/checksums/3f/3fafecfb15585ede6b840158cbc2f399" end it "has the path the file's subdirectory in the checksum repo" do @storage.checksum_repo_directory.should == "/var/chef/checksums/3f" end it "commits a file from a given location to the checksum repo location" do File.should_receive(:rename).with("/tmp/arbitrary_file_location", @storage.file_location) FileUtils.should_receive(:mkdir_p).with("/var/chef/checksums/3f") @storage.commit("/tmp/arbitrary_file_location") end it "reverts committing a file" do File.should_receive(:rename).with("/tmp/arbitrary_file_location", @storage.file_location) FileUtils.should_receive(:mkdir_p).with("/var/chef/checksums/3f") @storage.commit("/tmp/arbitrary_file_location") File.should_receive(:rename).with(@storage.file_location, "/tmp/arbitrary_file_location") @storage.revert("/tmp/arbitrary_file_location") end it "deletes the file" do FileUtils.should_receive(:rm).with(@storage.file_location) @storage.purge end it "successfully purges even if its file has been deleted from the repo" do FileUtils.should_receive(:rm).with(@storage.file_location).and_raise(Errno::ENOENT) lambda {@storage.purge}.should_not raise_error end end chef-11.8.2/spec/unit/node/0000755000004100000410000000000012254362222015376 5ustar www-datawww-datachef-11.8.2/spec/unit/node/immutable_collections_spec.rb0000644000004100000410000000675512254362222023327 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require "chef/node/immutable_collections" describe Chef::Node::ImmutableMash do before do @data_in = {:top => {:second_level => "some value"}, "top_level_2" => %w[array of values], :top_level_3 => [{:hash_array => 1, :hash_array_b => 2}], :top_level_4 => {:level2 => {:key => "value"}} } @immutable_mash = Chef::Node::ImmutableMash.new(@data_in) end it "element references like regular hash" do @immutable_mash[:top][:second_level].should == "some value" end it "elelment references like a regular Mash" do @immutable_mash[:top_level_2].should == %w[array of values] end it "converts Hash-like inputs into ImmutableMash's" do @immutable_mash[:top].should be_a(Chef::Node::ImmutableMash) end it "converts array inputs into ImmutableArray's" do @immutable_mash[:top_level_2].should be_a(Chef::Node::ImmutableArray) end it "converts arrays of hashes to ImmutableArray's of ImmutableMashes" do @immutable_mash[:top_level_3].first.should be_a(Chef::Node::ImmutableMash) end it "converts nested hashes to ImmutableMashes" do @immutable_mash[:top_level_4].should be_a(Chef::Node::ImmutableMash) @immutable_mash[:top_level_4][:level2].should be_a(Chef::Node::ImmutableMash) end [ :[]=, :clear, :default=, :default_proc=, :delete, :delete_if, :keep_if, :merge!, :update, :reject!, :replace, :select!, :shift ].each do |mutator| it "doesn't allow mutation via `#{mutator}'" do lambda { @immutable_mash.send(mutator) }.should raise_error(Chef::Exceptions::ImmutableAttributeModification) end end it "returns a mutable version of itself when duped" do mutable = @immutable_mash.dup mutable[:new_key] = :value mutable[:new_key].should == :value end end describe Chef::Node::ImmutableArray do before do @immutable_array = Chef::Node::ImmutableArray.new(%w[foo bar baz]) end ## # Note: other behaviors, such as immutibilizing input data, are tested along # with ImmutableMash, above ### [ :<<, :[]=, :clear, :collect!, :compact!, :default=, :default_proc=, :delete, :delete_at, :delete_if, :fill, :flatten!, :insert, :keep_if, :map!, :merge!, :pop, :push, :update, :reject!, :reverse!, :replace, :select!, :shift, :slice!, :sort!, :sort_by!, :uniq!, :unshift ].each do |mutator| it "does not allow mutation via `#{mutator}" do lambda { @immutable_array.send(mutator)}.should raise_error(Chef::Exceptions::ImmutableAttributeModification) end end it "returns a mutable version of itself when duped" do mutable = @immutable_array.dup mutable[0] = :value mutable[0].should == :value end end chef-11.8.2/spec/unit/node/attribute_spec.rb0000644000004100000410000010776212254362222020755 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/node/attribute' describe Chef::Node::Attribute do before(:each) do @attribute_hash = {"dmi"=>{}, "command"=>{"ps"=>"ps -ef"}, "platform_version"=>"10.5.7", "platform"=>"mac_os_x", "ipaddress"=>"192.168.0.117", "network"=> {"default_interface"=>"en1", "interfaces"=> {"vmnet1"=> {"flags"=> ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"], "number"=>"1", "addresses"=> {"00:50:56:c0:00:01"=>{"family"=>"lladdr"}, "192.168.110.1"=> {"broadcast"=>"192.168.110.255", "netmask"=>"255.255.255.0", "family"=>"inet"}}, "mtu"=>"1500", "type"=>"vmnet", "arp"=>{"192.168.110.255"=>"ff:ff:ff:ff:ff:ff"}, "encapsulation"=>"Ethernet"}, "stf0"=> {"flags"=>[], "number"=>"0", "addresses"=>{}, "mtu"=>"1280", "type"=>"stf", "encapsulation"=>"6to4"}, "lo0"=> {"flags"=>["UP", "LOOPBACK", "RUNNING", "MULTICAST"], "number"=>"0", "addresses"=> {"::1"=>{"scope"=>"Node", "prefixlen"=>"128", "family"=>"inet6"}, "127.0.0.1"=>{"netmask"=>"255.0.0.0", "family"=>"inet"}, "fe80::1"=>{"scope"=>"Link", "prefixlen"=>"64", "family"=>"inet6"}}, "mtu"=>"16384", "type"=>"lo", "encapsulation"=>"Loopback"}, "gif0"=> {"flags"=>["POINTOPOINT", "MULTICAST"], "number"=>"0", "addresses"=>{}, "mtu"=>"1280", "type"=>"gif", "encapsulation"=>"IPIP"}, "vmnet8"=> {"flags"=> ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"], "number"=>"8", "addresses"=> {"192.168.4.1"=> {"broadcast"=>"192.168.4.255", "netmask"=>"255.255.255.0", "family"=>"inet"}, "00:50:56:c0:00:08"=>{"family"=>"lladdr"}}, "mtu"=>"1500", "type"=>"vmnet", "arp"=>{"192.168.4.255"=>"ff:ff:ff:ff:ff:ff"}, "encapsulation"=>"Ethernet"}, "en0"=> {"status"=>"inactive", "flags"=> ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"], "number"=>"0", "addresses"=>{"00:23:32:b0:32:f2"=>{"family"=>"lladdr"}}, "mtu"=>"1500", "media"=> {"supported"=> {"autoselect"=>{"options"=>[]}, "none"=>{"options"=>[]}, "1000baseT"=> {"options"=>["full-duplex", "flow-control", "hw-loopback"]}, "10baseT/UTP"=> {"options"=> ["half-duplex", "full-duplex", "flow-control", "hw-loopback"]}, "100baseTX"=> {"options"=> ["half-duplex", "full-duplex", "flow-control", "hw-loopback"]}}, "selected"=>{"autoselect"=>{"options"=>[]}}}, "type"=>"en", "encapsulation"=>"Ethernet"}, "en1"=> {"status"=>"active", "flags"=> ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"], "number"=>"1", "addresses"=> {"fe80::223:6cff:fe7f:676c"=> {"scope"=>"Link", "prefixlen"=>"64", "family"=>"inet6"}, "00:23:6c:7f:67:6c"=>{"family"=>"lladdr"}, "192.168.0.117"=> {"broadcast"=>"192.168.0.255", "netmask"=>"255.255.255.0", "family"=>"inet"}}, "mtu"=>"1500", "media"=> {"supported"=>{"autoselect"=>{"options"=>[]}}, "selected"=>{"autoselect"=>{"options"=>[]}}}, "type"=>"en", "arp"=> {"192.168.0.72"=>"0:f:ea:39:fa:d5", "192.168.0.1"=>"0:1c:fb:fc:6f:20", "192.168.0.255"=>"ff:ff:ff:ff:ff:ff", "192.168.0.3"=>"0:1f:33:ea:26:9b", "192.168.0.77"=>"0:23:12:70:f8:cf", "192.168.0.152"=>"0:26:8:7d:2:4c"}, "encapsulation"=>"Ethernet"}, "en2"=> {"status"=>"active", "flags"=> ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"], "number"=>"2", "addresses"=> {"169.254.206.152"=> {"broadcast"=>"169.254.255.255", "netmask"=>"255.255.0.0", "family"=>"inet"}, "00:1c:42:00:00:01"=>{"family"=>"lladdr"}, "fe80::21c:42ff:fe00:1"=> {"scope"=>"Link", "prefixlen"=>"64", "family"=>"inet6"}}, "mtu"=>"1500", "media"=> {"supported"=>{"autoselect"=>{"options"=>[]}}, "selected"=>{"autoselect"=>{"options"=>[]}}}, "type"=>"en", "encapsulation"=>"Ethernet"}, "fw0"=> {"status"=>"inactive", "flags"=>["BROADCAST", "SIMPLEX", "MULTICAST"], "number"=>"0", "addresses"=>{"00:23:32:ff:fe:b0:32:f2"=>{"family"=>"lladdr"}}, "mtu"=>"4078", "media"=> {"supported"=>{"autoselect"=>{"options"=>["full-duplex"]}}, "selected"=>{"autoselect"=>{"options"=>["full-duplex"]}}}, "type"=>"fw", "encapsulation"=>"1394"}, "en3"=> {"status"=>"active", "flags"=> ["UP", "BROADCAST", "SMART", "RUNNING", "SIMPLEX", "MULTICAST"], "number"=>"3", "addresses"=> {"169.254.206.152"=> {"broadcast"=>"169.254.255.255", "netmask"=>"255.255.0.0", "family"=>"inet"}, "00:1c:42:00:00:00"=>{"family"=>"lladdr"}, "fe80::21c:42ff:fe00:0"=> {"scope"=>"Link", "prefixlen"=>"64", "family"=>"inet6"}}, "mtu"=>"1500", "media"=> {"supported"=>{"autoselect"=>{"options"=>[]}}, "selected"=>{"autoselect"=>{"options"=>[]}}}, "type"=>"en", "encapsulation"=>"Ethernet"}}}, "fqdn"=>"latte.local", "ohai_time"=>1249065590.90391, "domain"=>"local", "os"=>"darwin", "platform_build"=>"9J61", "os_version"=>"9.7.0", "hostname"=>"latte", "macaddress"=>"00:23:6c:7f:67:6c", "music" => { "jimmy_eat_world" => "nice", "apophis" => false } } @default_hash = { "domain" => "opscode.com", "hot" => { "day" => "saturday" }, "music" => { "jimmy_eat_world" => "is fun!", "mastodon" => "rocks", "mars_volta" => "is loud and nutty", "deeper" => { "gates_of_ishtar" => nil }, "this" => {"apparatus" => {"must" => "be unearthed"}} } } @override_hash = { "macaddress" => "00:00:00:00:00:00", "hot" => { "day" => "sunday" }, "fire" => "still burn", "music" => { "mars_volta" => "cicatriz" } } @automatic_hash = {"week" => "friday"} @attributes = Chef::Node::Attribute.new(@attribute_hash, @default_hash, @override_hash, @automatic_hash) end describe "initialize" do it "should return a Chef::Node::Attribute" do @attributes.should be_a_kind_of(Chef::Node::Attribute) end it "should take an Automatioc, Normal, Default and Override hash" do lambda { Chef::Node::Attribute.new({}, {}, {}, {}) }.should_not raise_error end [ :normal, :default, :override, :automatic ].each do |accessor| it "should set #{accessor}" do na = Chef::Node::Attribute.new({ :normal => true }, { :default => true }, { :override => true }, { :automatic => true }) na.send(accessor).should == { accessor.to_s => true } end end it "should be enumerable" do @attributes.should be_is_a(Enumerable) end end describe "when printing attribute components" do it "does not cause a type error" do # See CHEF-3799; IO#puts implicitly calls #to_ary on its argument. This # is expected to raise a NoMethodError or return an Array. `to_ary` is # the "strict" conversion method that should only be implemented by # things that are truly Array-like, so NoMethodError is the right choice. # (cf. there is no Hash#to_ary). lambda { @attributes.default.to_ary }.should raise_error(NoMethodError) end end describe "when debugging attributes" do before do @attributes.default[:foo][:bar] = "default" @attributes.env_default[:foo][:bar] = "env_default" @attributes.role_default[:foo][:bar] = "role_default" @attributes.force_default[:foo][:bar] = "force_default" @attributes.normal[:foo][:bar] = "normal" @attributes.override[:foo][:bar] = "override" @attributes.role_override[:foo][:bar] = "role_override" @attributes.env_override[:foo][:bar] = "env_override" @attributes.force_override[:foo][:bar] = "force_override" @attributes.automatic[:foo][:bar] = "automatic" end it "gives the value at each level of precedence for a path spec" do expected = [["set_unless_enabled?", false], ["default", "default"], ["env_default", "env_default"], ["role_default", "role_default"], ["force_default", "force_default"], ["normal", "normal"], ["override", "override"], ["role_override", "role_override"], ["env_override", "env_override"], ["force_override", "force_override"], ["automatic", "automatic"] ] @attributes.debug_value(:foo, :bar).should == expected end end describe "when fetching values based on precedence" do before do @attributes.default["default"] = "cookbook default" @attributes.override["override"] = "cookbook override" end it "prefers 'forced default' over any other default" do @attributes.default!["default"] = "force default" @attributes.role_default["default"] = "role default" @attributes.env_default["default"] = "environment default" @attributes["default"].should == "force default" end it "prefers role_default over environment or cookbook default" do @attributes.role_default["default"] = "role default" @attributes.env_default["default"] = "environment default" @attributes["default"].should == "role default" end it "prefers environment default over cookbook default" do @attributes.env_default["default"] = "environment default" @attributes["default"].should == "environment default" end it "returns the cookbook default when no other default values are present" do @attributes["default"].should == "cookbook default" end it "prefers 'forced overrides' over role or cookbook overrides" do @attributes.override!["override"] = "force override" @attributes.env_override["override"] = "environment override" @attributes.role_override["override"] = "role override" @attributes["override"].should == "force override" end it "prefers environment overrides over role or cookbook overrides" do @attributes.env_override["override"] = "environment override" @attributes.role_override["override"] = "role override" @attributes["override"].should == "environment override" end it "prefers role overrides over cookbook overrides" do @attributes.role_override["override"] = "role override" @attributes["override"].should == "role override" end it "returns cookbook overrides when no other overrides are present" do @attributes["override"].should == "cookbook override" end it "merges arrays within the default precedence" do @attributes.role_default["array"] = %w{role} @attributes.env_default["array"] = %w{env} @attributes["array"].should == %w{env role} end it "merges arrays within the override precedence" do @attributes.role_override["array"] = %w{role} @attributes.env_override["array"] = %w{env} @attributes["array"].should == %w{role env} end it "does not merge arrays between default and normal" do @attributes.role_default["array"] = %w{role} @attributes.normal["array"] = %w{normal} @attributes["array"].should == %w{normal} end it "does not merge arrays between normal and override" do @attributes.normal["array"] = %w{normal} @attributes.role_override["array"] = %w{role} @attributes["array"].should == %w{role} end it "merges nested hashes between precedence levels" do @attributes = Chef::Node::Attribute.new({}, {}, {}, {}) @attributes.env_default = {"a" => {"b" => {"default" => "default"}}} @attributes.normal = {"a" => {"b" => {"normal" => "normal"}}} @attributes.override = {"a" => {"override" => "role"}} @attributes.automatic = {"a" => {"automatic" => "auto"}} @attributes["a"].should == {"b"=>{"default"=>"default", "normal"=>"normal"}, "override"=>"role", "automatic"=>"auto"} end end describe "when reading combined default or override values" do before do @attributes.default["cd"] = "cookbook default" @attributes.role_default["rd"] = "role default" @attributes.env_default["ed"] = "env default" @attributes.default!["fd"] = "force default" @attributes.override["co"] = "cookbook override" @attributes.role_override["ro"] = "role override" @attributes.env_override["eo"] = "env override" @attributes.override!["fo"] = "force override" end it "merges all types of overrides into a combined override" do @attributes.combined_override["co"].should == "cookbook override" @attributes.combined_override["ro"].should == "role override" @attributes.combined_override["eo"].should == "env override" @attributes.combined_override["fo"].should == "force override" end it "merges all types of defaults into a combined default" do @attributes.combined_default["cd"].should == "cookbook default" @attributes.combined_default["rd"].should == "role default" @attributes.combined_default["ed"].should == "env default" @attributes.combined_default["fd"].should == "force default" end end describe "[]" do it "should return override data if it exists" do @attributes["macaddress"].should == "00:00:00:00:00:00" end it "should return attribute data if it is not overridden" do @attributes["platform"].should == "mac_os_x" end it "should return data that doesn't have corresponding keys in every hash" do @attributes["command"]["ps"].should == "ps -ef" end it "should return default data if it is not overriden or in attribute data" do @attributes["music"]["mastodon"].should == "rocks" end it "should prefer the override data over an available default" do @attributes["music"]["mars_volta"].should == "cicatriz" end it "should prefer the attribute data over an available default" do @attributes["music"]["jimmy_eat_world"].should == "nice" end it "should prefer override data over default data if there is no attribute data" do @attributes["hot"]["day"].should == "sunday" end it "should return the merged hash if all three have values" do result = @attributes["music"] result["mars_volta"].should == "cicatriz" result["jimmy_eat_world"].should == "nice" result["mastodon"].should == "rocks" end end describe "[]=" do it "should error out when the type of attribute to set has not been specified" do @attributes.normal["the_ghost"] = { } lambda { @attributes["the_ghost"]["exterminate"] = false }.should raise_error(Chef::Exceptions::ImmutableAttributeModification) end it "should let you set an attribute value when another hash has an intermediate value" do @attributes.normal["the_ghost"] = { "exterminate" => "the future" } lambda { @attributes.normal["the_ghost"]["exterminate"]["tomorrow"] = false }.should_not raise_error(NoMethodError) end it "should set the attribute value" do @attributes.normal["longboard"] = "surfing" @attributes.normal["longboard"].should == "surfing" @attributes.normal["longboard"].should == "surfing" end it "should set deeply nested attribute values when a precedence level is specified" do @attributes.normal["deftones"]["hunters"]["nap"] = "surfing" @attributes.normal["deftones"]["hunters"]["nap"].should == "surfing" end it "should die if you try and do nested attributes that do not exist without read vivification" do lambda { @attributes["foo"]["bar"] = :baz }.should raise_error end it "should let you set attributes manually without vivification" do @attributes.normal["foo"] = Mash.new @attributes.normal["foo"]["bar"] = :baz @attributes.normal["foo"]["bar"].should == :baz end it "should optionally skip setting the value if one already exists" do @attributes.set_unless_value_present = true @attributes.normal["hostname"] = "bar" @attributes["hostname"].should == "latte" end it "does not support ||= when setting" do # This is a limitation of auto-vivification. # Users who need this behavior can use set_unless and friends @attributes.normal["foo"] = Mash.new @attributes.normal["foo"]["bar"] ||= "stop the world" @attributes.normal["foo"]["bar"].should == {} end end describe "to_hash" do it "should convert to a hash" do @attributes.to_hash.class.should == Hash end it "should convert to a hash based on current state" do hash = @attributes["hot"].to_hash hash.class.should == Hash hash["day"].should == "sunday" end end describe "has_key?" do it "should return true if an attribute exists" do @attributes.has_key?("music").should == true end it "should return false if an attribute does not exist" do @attributes.has_key?("ninja").should == false end it "should return false if an attribute does not exist using dot notation" do @attributes.has_key?("does_not_exist_at_all").should == false end it "should return true if an attribute exists but is set to nil using dot notation" do @attributes.music.deeper.has_key?("gates_of_ishtar").should == true end it "should return true if an attribute exists but is set to false" do @attributes.has_key?("music") @attributes["music"].has_key?("apophis").should == true end it "does not find keys above the current nesting level" do @attributes["music"]["this"]["apparatus"].should_not have_key("this") end it "does not find keys below the current nesting level" do @attributes["music"]["this"].should_not have_key("must") end [:include?, :key?, :member?].each do |method| it "should alias the method #{method} to itself" do @attributes.should respond_to(method) end it "#{method} should behave like has_key?" do @attributes.send(method, "music").should == true end end end describe "attribute?" do it "should return true if an attribute exists" do @attributes.attribute?("music").should == true end it "should return false if an attribute does not exist" do @attributes.attribute?("ninja").should == false end end describe "method_missing" do it "should behave like a [] lookup" do @attributes.music.mastodon.should == "rocks" end it "should allow the last method to set a value if it has an = sign on the end" do @attributes.normal.music.mastodon = [ "dream", "still", "shining" ] @attributes.reset @attributes.normal.music.mastodon.should == [ "dream", "still", "shining" ] end end describe "keys" do before(:each) do @attributes = Chef::Node::Attribute.new( { "one" => { "two" => "three" }, "hut" => { "two" => "three" }, "place" => { } }, { "one" => { "four" => "five" }, "snakes" => "on a plane" }, { "one" => { "six" => "seven" }, "snack" => "cookies" }, {} ) end it "should yield each top level key" do collect = Array.new @attributes.keys.each do |k| collect << k end collect.include?("one").should == true collect.include?("hut").should == true collect.include?("snakes").should == true collect.include?("snack").should == true collect.include?("place").should == true collect.length.should == 5 end it "should yield lower if we go deeper" do collect = Array.new @attributes.one.keys.each do |k| collect << k end collect.include?("two").should == true collect.include?("four").should == true collect.include?("six").should == true collect.length.should == 3 end it "should not raise an exception if one of the hashes has a nil value on a deep lookup" do lambda { @attributes.place.keys { |k| } }.should_not raise_error(NoMethodError) end end describe "each" do before(:each) do @attributes = Chef::Node::Attribute.new( { "one" => "two", "hut" => "three", }, { "one" => "four", "snakes" => "on a plane" }, { "one" => "six", "snack" => "cookies" }, {} ) end it "should yield each top level key and value, post merge rules" do collect = Hash.new @attributes.each do |k, v| collect[k] = v end collect["one"].should == "six" collect["hut"].should == "three" collect["snakes"].should == "on a plane" collect["snack"].should == "cookies" end it "should yield as a two-element array" do @attributes.each do |a| a.should be_an_instance_of(Array) end end end describe "each_key" do before do @attributes = Chef::Node::Attribute.new( { "one" => "two", "hut" => "three", }, { "one" => "four", "snakes" => "on a plane" }, { "one" => "six", "snack" => "cookies" }, {} ) end it "should respond to each_key" do @attributes.should respond_to(:each_key) end it "should yield each top level key, post merge rules" do collect = Array.new @attributes.each_key do |k| collect << k end collect.should include("one") collect.should include("snack") collect.should include("hut") collect.should include("snakes") end end describe "each_pair" do before do @attributes = Chef::Node::Attribute.new( { "one" => "two", "hut" => "three", }, { "one" => "four", "snakes" => "on a plane" }, { "one" => "six", "snack" => "cookies" }, {} ) end it "should respond to each_pair" do @attributes.should respond_to(:each_pair) end it "should yield each top level key and value pair, post merge rules" do collect = Hash.new @attributes.each_pair do |k, v| collect[k] = v end collect["one"].should == "six" collect["hut"].should == "three" collect["snakes"].should == "on a plane" collect["snack"].should == "cookies" end end describe "each_value" do before do @attributes = Chef::Node::Attribute.new( { "one" => "two", "hut" => "three", }, { "one" => "four", "snakes" => "on a plane" }, { "one" => "six", "snack" => "cookies" }, {} ) end it "should respond to each_value" do @attributes.should respond_to(:each_value) end it "should yield each value, post merge rules" do collect = Array.new @attributes.each_value do |v| collect << v end collect.should include("cookies") collect.should include("three") collect.should include("on a plane") end it "should yield four elements" do collect = Array.new @attributes.each_value do |v| collect << v end collect.length.should == 4 end end describe "empty?" do before do @attributes = Chef::Node::Attribute.new( { "one" => "two", "hut" => "three", }, { "one" => "four", "snakes" => "on a plane" }, { "one" => "six", "snack" => "cookies" }, {} ) @empty = Chef::Node::Attribute.new({}, {}, {}, {}) end it "should respond to empty?" do @attributes.should respond_to(:empty?) end it "should return true when there are no keys" do @empty.empty?.should == true end it "should return false when there are keys" do @attributes.empty?.should == false end end describe "fetch" do before do @attributes = Chef::Node::Attribute.new( { "one" => "two", "hut" => "three", }, { "one" => "four", "snakes" => "on a plane" }, { "one" => "six", "snack" => "cookies" }, {} ) end it "should respond to fetch" do @attributes.should respond_to(:fetch) end describe "when the key exists" do it "should return the value of the key, post merge (same result as each)" do { "one" => "six", "hut" => "three", "snakes" => "on a plane", "snack" => "cookies" }.each do |k,v| @attributes.fetch(k).should == v end end end describe "when the key does not exist" do describe "and no args are passed" do it "should raise an indexerror" do lambda { @attributes.fetch("lololol") }.should raise_error(IndexError) end end describe "and a default arg is passed" do it "should return the value of the default arg" do @attributes.fetch("lol", "blah").should == "blah" end end describe "and a block is passed" do it "should run the block and return its value" do @attributes.fetch("lol") { |x| "#{x}, blah" }.should == "lol, blah" end end end end describe "has_value?" do before do @attributes = Chef::Node::Attribute.new( { "one" => "two", "hut" => "three", }, { "one" => "four", "snakes" => "on a plane" }, { "one" => "six", "snack" => "cookies" }, {} ) end it "should respond to has_value?" do @attributes.should respond_to(:has_value?) end it "should return true if any key has the value supplied" do @attributes.has_value?("cookies").should == true end it "should return false no key has the value supplied" do @attributes.has_value?("lololol").should == false end it "should alias value?" do @attributes.should respond_to(:value?) end end describe "index" do before do @attributes = Chef::Node::Attribute.new( { "one" => "two", "hut" => "three", }, { "one" => "four", "snakes" => "on a plane" }, { "one" => "six", "snack" => "cookies" }, {} ) end it "should respond to index" do @attributes.should respond_to(:index) end describe "when the value is indexed" do it "should return the index" do @attributes.index("six").should == "one" end end describe "when the value is not indexed" do it "should return nil" do @attributes.index("lolol").should == nil end end end describe "values" do before do @attributes = Chef::Node::Attribute.new( { "one" => "two", "hut" => "three", }, { "one" => "four", "snakes" => "on a plane" }, { "one" => "six", "snack" => "cookies" }, {} ) end it "should respond to values" do @attributes.should respond_to(:values) end it "should return an array of values" do @attributes.values.length.should == 4 end it "should match the values output from each" do @attributes.values.should include("six") @attributes.values.should include("cookies") @attributes.values.should include("three") @attributes.values.should include("on a plane") end end describe "select" do before do @attributes = Chef::Node::Attribute.new( { "one" => "two", "hut" => "three", }, { "one" => "four", "snakes" => "on a plane" }, { "one" => "six", "snack" => "cookies" }, {} ) end it "should respond to select" do @attributes.should respond_to(:select) end if RUBY_VERSION >= "1.8.7" it "should not raise a LocalJumpError if no block is given" do lambda { @attributes.select }.should_not raise_error(LocalJumpError) end else it "should raise a LocalJumpError if no block is given" do lambda{ @attributes.select }.should raise_error(LocalJumpError) end end it "should return an empty hash/array (ruby-version-dependent) for a block containing nil" do @attributes.select { nil }.should == {}.select { nil } end # sorted for spec clarity it "should return a new array of k,v pairs for which the block returns true" do @attributes.select { true }.sort.should == ( [ ["hut", "three"], ["one", "six"], ["snack", "cookies"], ["snakes", "on a plane"] ] ) end end describe "size" do before do @attributes = Chef::Node::Attribute.new( { "one" => "two", "hut" => "three", }, { "one" => "four", "snakes" => "on a plane" }, { "one" => "six", "snack" => "cookies" }, {} ) @empty = Chef::Node::Attribute.new({},{},{},{}) end it "should respond to size" do @attributes.should respond_to(:size) end it "should alias length to size" do @attributes.should respond_to(:length) end it "should return 0 for an empty attribute" do @empty.size.should == 0 end it "should return the number of pairs" do @attributes.size.should == 4 end end describe "kind_of?" do it "should falsely inform you that it is a Hash" do @attributes.should be_a_kind_of(Hash) end it "should falsely inform you that it is a Mash" do @attributes.should be_a_kind_of(Mash) end it "should inform you that it is a Chef::Node::Attribute" do @attributes.should be_a_kind_of(Chef::Node::Attribute) end it "should inform you that it is anything else" do @attributes.should_not be_a_kind_of(Chef::Node) end end describe "inspect" do it "should be readable" do # NOTE: previous implementation hid the values, showing @automatic={...} # That is nice and compact, but hides a lot of info, which seems counter # to the point of calling #inspect... @attributes.inspect.should =~ /@automatic=\{.*\}/ @attributes.inspect.should =~ /@normal=\{.*\}/ end end # For expedience, this test is implementation-heavy. describe "when a component attribute is mutated" do [ :clear, :shift ].each do |mutator| it "resets the cache when the mutator #{mutator} is called" do @attributes.should_receive(:reset_cache) @attributes.default.send(mutator) end end it "resets the cache when the mutator delete is called" do @attributes.should_receive(:reset_cache) @attributes.default.delete(:music) end [ :merge!, :update, :replace ].each do |mutator| it "resets the cache when the mutator #{mutator} is called" do # Implementation of Mash means that this could get called many times. That's okay. @attributes.should_receive(:reset_cache).at_least(1).times @attributes.default.send(mutator, {:foo => :bar}) end end [ :delete_if, :keep_if, :reject!, :select!, ].each do |mutator| it "resets the cache when the mutator #{mutator} is called" do # Implementation of Mash means that this could get called many times. That's okay. @attributes.should_receive(:reset_cache).at_least(1).times block = lambda {|k,v| true } @attributes.default.send(mutator, &block) end end end describe "when not mutated" do it "does not reset the cache when dup'd [CHEF-3680]" do @attributes.default[:foo][:bar] = "set on original" subtree = @attributes[:foo] @attributes.default[:foo].dup[:bar] = "set on dup" subtree[:bar].should == "set on original" end end describe "when setting a component attribute to a new value" do it "converts the input in to a VividMash tree (default)" do @attributes.default = {} @attributes.default.foo = "bar" @attributes.merged_attributes[:foo].should == "bar" end it "converts the input in to a VividMash tree (normal)" do @attributes.normal = {} @attributes.normal.foo = "bar" @attributes.merged_attributes[:foo].should == "bar" end it "converts the input in to a VividMash tree (override)" do @attributes.override = {} @attributes.override.foo = "bar" @attributes.merged_attributes[:foo].should == "bar" end it "converts the input in to a VividMash tree (automatic)" do @attributes.automatic = {} @attributes.automatic.foo = "bar" @attributes.merged_attributes[:foo].should == "bar" end end describe "when attemping to write without specifying precedence" do it "raises an error when using []=" do lambda { @attributes[:new_key] = "new value" }.should raise_error(Chef::Exceptions::ImmutableAttributeModification) end it "raises an error when using `attr=value`" do lambda { @attributes.new_key = "new value" }.should raise_error(Chef::Exceptions::ImmutableAttributeModification) end end end chef-11.8.2/spec/unit/file_access_control_spec.rb0000644000004100000410000002731512254362222022020 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'ostruct' describe Chef::FileAccessControl do describe "Unix" do before do platform_mock :unix do # we have to re-load the file so the proper # platform specific module is mixed in @node = Chef::Node.new load File.join(File.dirname(__FILE__), "..", "..", "lib", "chef", "file_access_control.rb") @resource = Chef::Resource::File.new('/tmp/a_file.txt') @resource.owner('toor') @resource.group('wheel') @resource.mode('0400') @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @current_resource = Chef::Resource::File.new('/tmp/different_file.txt') @provider_requirements = Chef::Provider::ResourceRequirements.new(@resource, @run_context) @provider = mock("File provider", :requirements => @provider_requirements, :manage_symlink_access? => false) @fac = Chef::FileAccessControl.new(@current_resource, @resource, @provider) end end it "has a resource" do @fac.resource.should equal(@resource) end it "has a file to manage" do @fac.file.should == '/tmp/different_file.txt' end it "is not modified yet" do @fac.should_not be_modified end it "determines the uid of the owner specified by the resource" do Etc.should_receive(:getpwnam).with('toor').and_return(OpenStruct.new(:uid => 2342)) @fac.target_uid.should == 2342 end it "raises a Chef::Exceptions::UserIDNotFound error when Etc can't find the user's name" do Etc.should_receive(:getpwnam).with('toor').and_raise(ArgumentError) lambda { @fac.target_uid ; @provider_requirements.run(:create) }.should raise_error(Chef::Exceptions::UserIDNotFound, "cannot determine user id for 'toor', does the user exist on this system?") end it "does not attempt to resolve the uid if the user is not specified" do resource = Chef::Resource::File.new("a file") fac = Chef::FileAccessControl.new(@current_resource, resource, @provider) fac.target_uid.should be_nil end it "does not want to update the owner if none is specified" do resource = Chef::Resource::File.new("a file") fac = Chef::FileAccessControl.new(@current_resource, resource, @provider) fac.should_update_owner?.should be_false end it "raises an ArgumentError if the resource's owner is set to something wack" do @resource.instance_variable_set(:@owner, :diaf) lambda { @fac.target_uid ; @provider_requirements.run(:create) }.should raise_error(ArgumentError) end it "uses the resource's uid for the target uid when the resource's owner is specified by an integer" do @resource.owner(2342) @fac.target_uid.should == 2342 end it "wraps uids to their negative complements to correctly handle negative uids" do # More: Mac OS X (at least) has negative UIDs for 'nobody' and some other # users. Ruby doesn't believe in negative UIDs so you get the diminished radix # complement (i.e., it wraps around the maximum size of C unsigned int) of these # uids. So we have to get ruby and negative uids to smoke the peace pipe # with each other. @resource.owner('nobody') Etc.should_receive(:getpwnam).with('nobody').and_return(OpenStruct.new(:uid => (4294967294))) @fac.target_uid.should == -2 end it "does not wrap uids to their negative complements beyond -9" do # More: when OSX userIDs are created by ActiveDirectory sync, it tends to use huge numbers # which had been incorrectly wrapped. It does not look like the OSX IDs go below -2 @resource.owner('bigdude') Etc.should_receive(:getpwnam).with('bigdude').and_return(OpenStruct.new(:uid => (4294967286))) @fac.target_uid.should == 4294967286 end it "wants to update the owner when the current owner is nil (creating a file)" do @current_resource.owner(nil) @resource.owner(2342) @fac.should_update_owner?.should be_true end it "wants to update the owner when the current owner doesn't match desired" do @current_resource.owner(3224) @resource.owner(2342) @fac.should_update_owner?.should be_true end it "includes updating ownership in its list of desired changes" do resource = Chef::Resource::File.new("a file") resource.owner(2342) @current_resource.owner(100) fac = Chef::FileAccessControl.new(@current_resource, resource, @provider) fac.describe_changes.should == ["change owner from '100' to '2342'"] end it "sets the file's owner as specified in the resource when the current owner is incorrect" do @resource.owner(2342) File.should_receive(:chown).with(2342, nil, '/tmp/different_file.txt') @fac.set_owner @fac.should be_modified end it "doesn't set the file's owner if it already matches" do @resource.owner(2342) @current_resource.owner(2342) File.should_not_receive(:chown) @fac.set_owner @fac.should_not be_modified end it "doesn't want to update a file's owner when it's already correct" do @resource.owner(2342) @current_resource.owner(2342) @fac.should_update_owner?.should be_false end it "determines the gid of the group specified by the resource" do Etc.should_receive(:getgrnam).with('wheel').and_return(OpenStruct.new(:gid => 2342)) @fac.target_gid.should == 2342 end it "uses a user specified gid as the gid" do @resource.group(2342) @fac.target_gid.should == 2342 end it "raises a Chef::Exceptions::GroupIDNotFound error when Etc can't find the user's name" do Etc.should_receive(:getgrnam).with('wheel').and_raise(ArgumentError) lambda { @fac.target_gid; @provider_requirements.run(:create) }.should raise_error(Chef::Exceptions::GroupIDNotFound, "cannot determine group id for 'wheel', does the group exist on this system?") end it "does not attempt to resolve a gid when none is supplied" do resource = Chef::Resource::File.new('crab') fac = Chef::FileAccessControl.new(@current_resource, resource, @provider) fac.target_gid.should be_nil end it "does not want to update the group when no target group is specified" do resource = Chef::Resource::File.new('crab') fac = Chef::FileAccessControl.new(@current_resource, resource, @provider) fac.should_update_group?.should be_false end it "raises an error when the supplied group name is an alien" do @resource.instance_variable_set(:@group, :failburger) lambda { @fac.target_gid; @provider_requirements.run(:create) }.should raise_error(ArgumentError) end it "wants to update the group when the current group is nil (creating a file)" do @resource.group(2342) @current_resource.group(nil) @fac.should_update_group?.should be_true end it "wants to update the group when the current group doesn't match the target group" do @resource.group(2342) @current_resource.group(815) @fac.should_update_group?.should be_true end it "includes updating the group in the list of changes" do resource = Chef::Resource::File.new('crab') resource.group(2342) @current_resource.group(815) fac = Chef::FileAccessControl.new(@current_resource, resource, @provider) fac.describe_changes.should == ["change group from '815' to '2342'"] end it "sets the file's group as specified in the resource when the group is not correct" do @resource.group(2342) @current_resource.group(815) File.should_receive(:chown).with(nil, 2342, '/tmp/different_file.txt') @fac.set_group @fac.should be_modified end it "doesn't want to modify the file's group when the current group is correct" do @resource.group(2342) @current_resource.group(2342) @fac.should_update_group?.should be_false end it "doesnt set the file's group if it is already correct" do @resource.group(2342) @current_resource.group(2342) # @fac.stub!(:stat).and_return(OpenStruct.new(:gid => 2342)) File.should_not_receive(:chown) @fac.set_group @fac.should_not be_modified end it "uses the supplied mode as octal when it's a string" do @resource.mode('444') @fac.target_mode.should == 292 # octal 444 => decimal 292 end it "uses the supplied mode verbatim when it's an integer" do @resource.mode(00444) @fac.target_mode.should == 292 end it "does not try to determine the mode when none is given" do resource = Chef::Resource::File.new('blahblah') fac = Chef::FileAccessControl.new(@current_resource, resource, @provider) fac.target_mode.should be_nil end it "doesn't want to update the mode when no target mode is given" do resource = Chef::Resource::File.new('blahblah') fac = Chef::FileAccessControl.new(@current_resource, resource, @provider) fac.should_update_mode?.should be_false end it "wants to update the mode when the current mode is nil (creating a file)" do @resource.mode("0400") @current_resource.mode(nil) @fac.should_update_mode?.should be_true end it "wants to update the mode when the desired mode does not match the current mode" do @resource.mode("0400") @current_resource.mode("0644") @fac.should_update_mode?.should be_true end it "includes changing the mode in the list of desired changes" do resource = Chef::Resource::File.new('blahblah') resource.mode("0750") @current_resource.mode("0444") fac = Chef::FileAccessControl.new(@current_resource, resource, @provider) fac.describe_changes.should == ["change mode from '0444' to '0750'"] end it "sets the file's mode as specified in the resource when the current modes are incorrect" do # stat returns modes like 0100644 (octal) => 33188 (decimal) #@fac.stub!(:stat).and_return(OpenStruct.new(:mode => 33188)) @current_resource.mode("0644") File.should_receive(:chmod).with(256, '/tmp/different_file.txt') @fac.set_mode @fac.should be_modified end it "does not want to update the mode when the current mode is correct" do @current_resource.mode("0400") @fac.should_update_mode?.should be_false end it "does not set the file's mode when the current modes are correct" do #@fac.stub!(:stat).and_return(OpenStruct.new(:mode => 0100400)) @current_resource.mode("0400") File.should_not_receive(:chmod) @fac.set_mode @fac.should_not be_modified end it "sets all access controls on a file" do @fac.stub!(:stat).and_return(OpenStruct.new(:owner => 99, :group => 99, :mode => 0100444)) @resource.mode(0400) @resource.owner(0) @resource.group(0) File.should_receive(:chmod).with(0400, '/tmp/different_file.txt') File.should_receive(:chown).with(0, nil, '/tmp/different_file.txt') File.should_receive(:chown).with(nil, 0, '/tmp/different_file.txt') @fac.set_all @fac.should be_modified end end end chef-11.8.2/spec/support/0000755000004100000410000000000012254362222015206 5ustar www-datawww-datachef-11.8.2/spec/support/platforms/0000755000004100000410000000000012254362222017215 5ustar www-datawww-datachef-11.8.2/spec/support/platforms/win32/0000755000004100000410000000000012254362222020157 5ustar www-datawww-datachef-11.8.2/spec/support/platforms/win32/spec_service.rb0000644000004100000410000000310212254362222023152 0ustar www-datawww-data# # Author:: Serdar Sutay () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'win32/daemon' class SpecService < ::Win32::Daemon def service_init @test_service_file = "#{ENV['TMP']}/spec_service_file" end def service_main(*startup_parameters) while running? do if !File.exists?(@test_service_file) File.open(@test_service_file, 'wb') do |f| f.write("This file is created by SpecService") end end sleep 1 end end ################################################################################ # Control Signal Callback Methods ################################################################################ def service_stop end def service_pause end def service_resume end def service_shutdown end end # To run this file as a service, it must be called as a script from within # the Windows Service framework. In that case, kick off the main loop! if __FILE__ == $0 SpecService.mainloop end chef-11.8.2/spec/support/platforms/prof/0000755000004100000410000000000012254362222020163 5ustar www-datawww-datachef-11.8.2/spec/support/platforms/prof/gc.rb0000644000004100000410000000311212254362222021076 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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 RSpec module Prof module GC class Profiler # GC 1 invokes. # Index Invoke Time(sec) Use Size(byte) Total Size(byte) Total Object GC time(ms) # 1 0.012 159240 212940 10647 0.00000000000001530000 LINE_PATTERN = /^\s+([\d\.]*)\s+([\d\.]*)\s+([\d\.]*)\s+([\d\.]*)\s+([\d\.]*)\s+([\d\.]*)$/ def start ::GC::Profiler.enable unless ::GC::Profiler.enabled? end def stop ::GC::Profiler.disable end def working_set_size begin ::GC.start ::GC::Profiler.result.scan(LINE_PATTERN)[-1][2].to_i if ::GC::Profiler.enabled? ensure ::GC::Profiler.clear end end def handle_count 0 end end end end end chef-11.8.2/spec/support/platforms/prof/win32.rb0000644000004100000410000000221712254362222021454 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/process' module RSpec module Prof module Win32 class Profiler def start GC.start end def stop GC.start end def working_set_size Chef::ReservedNames::Win32::Process.get_current_process.memory_info[:WorkingSetSize] end def handle_count Chef::ReservedNames::Win32::Process.get_current_process.handle_count end end end end end chef-11.8.2/spec/support/chef_helpers.rb0000644000004100000410000000561612254362222020172 0ustar www-datawww-data# Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # CHEF_SPEC_DATA = File.expand_path(File.dirname(__FILE__) + "/../data/") CHEF_SPEC_BACKUP_PATH = File.join(Dir.tmpdir, 'test-backup-path') Chef::Config[:log_level] = :fatal Chef::Config[:persistent_queue] = false Chef::Config[:file_backup_path] = CHEF_SPEC_BACKUP_PATH Chef::Log.level(Chef::Config.log_level) Chef::Config.solo(false) Chef::Log.logger = Logger.new(StringIO.new) def sha256_checksum(path) Digest::SHA256.hexdigest(File.read(path)) end # From Ruby 1.9.2+ # Here for backwards compatibility with Ruby 1.8.7 # http://rubydoc.info/stdlib/tmpdir/1.9.2/Dir/Tmpname def make_tmpname(prefix_suffix, n = nil) case prefix_suffix when String prefix = prefix_suffix suffix = "" when Array prefix = prefix_suffix[0] suffix = prefix_suffix[1] else raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}" end t = Time.now.strftime("%Y%m%d") path = "#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}" path << "-#{n}" if n path << suffix end # NOTE: # This is a temporary fix to get tests passing on systems that have no `diff` # until we can replace shelling out to `diff` with ruby diff-lcs def has_diff? begin diff_cmd = Mixlib::ShellOut.new("diff -v") diff_cmd.run_command true rescue Errno::ENOENT false end end # This is a helper to determine if the ruby in the PATH contains # win32/service gem. windows_service_manager tests create a windows # service that starts with the system ruby and requires this gem. def system_windows_service_gem? windows_service_gem_check_command = "ruby -e 'require \"win32/daemon\"' > /dev/null 2>&1" if defined?(Bundler) Bundler.with_clean_env do # This returns true if the gem can be loaded system windows_service_gem_check_command end else # This returns true if the gem can be loaded system windows_service_gem_check_command end end # This is a helper to canonicalize paths that we're using in the file # tests. def canonicalize_path(path) windows? ? path.gsub('/', '\\') : path end # Check if a cmd exists on the PATH def which(cmd) paths = ENV['PATH'].split(File::PATH_SEPARATOR) + [ '/bin', '/usr/bin', '/sbin', '/usr/sbin' ] paths.each do |path| filename = File.join(path, cmd) return filename if File.executable?(filename) end false end chef-11.8.2/spec/support/lib/0000755000004100000410000000000012254362222015754 5ustar www-datawww-datachef-11.8.2/spec/support/lib/chef/0000755000004100000410000000000012254362222016661 5ustar www-datawww-datachef-11.8.2/spec/support/lib/chef/resource/0000755000004100000410000000000012254362222020510 5ustar www-datawww-datachef-11.8.2/spec/support/lib/chef/resource/with_state.rb0000644000004100000410000000174212254362222023214 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008, 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' require 'chef/json_compat' class Chef class Resource class WithState < Chef::Resource attr_accessor :state def initialize(name, run_context=nil) @resource_name = :with_state super end def state @state end end end end chef-11.8.2/spec/support/lib/chef/resource/cat.rb0000644000004100000410000000204112254362222021601 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Resource class Cat < Chef::Resource attr_accessor :action def initialize(name, run_context=nil) @resource_name = :cat super @action = "sell" end def pretty_kitty(arg=nil) if arg == true or arg == false @pretty_kitty = arg end @pretty_kitty end end end end chef-11.8.2/spec/support/lib/chef/resource/one_two_three_four.rb0000644000004100000410000000213712254362222024734 0ustar www-datawww-data# # Author:: John Hampton () # Copyright:: Copyright (c) 2009 CleanOffer, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Resource class OneTwoThreeFour < Chef::Resource attr_reader :i_can_count def initialize(name, run_context) @resource_name = :one_two_three_four super end def i_can_count(tf) @i_can_count = tf end def something(arg=nil) if arg == true or arg == false @something = arg end @something end end end end chef-11.8.2/spec/support/lib/chef/resource/zen_master.rb0000644000004100000410000000216212254362222023205 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008, 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' require 'chef/json_compat' class Chef class Resource class ZenMaster < Chef::Resource attr_reader :peace def initialize(name, run_context=nil) @resource_name = :zen_master super end def peace(tf) @peace = tf end def something(arg=nil) if arg == true or arg == false @something = arg end @something end end end end chef-11.8.2/spec/support/lib/chef/provider/0000755000004100000410000000000012254362222020513 5ustar www-datawww-datachef-11.8.2/spec/support/lib/chef/provider/easy.rb0000644000004100000410000000161112254362222022000 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Provider class Easy < Chef::Provider def load_current_resource true end def action_sell true end def action_buy true end end end end chef-11.8.2/spec/support/lib/chef/provider/snakeoil.rb0000644000004100000410000000175612254362222022656 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Provider class SnakeOil < Chef::Provider def load_current_resource true end def action_purr @new_resource.updated_by_last_action(true) true end def action_sell true end def action_buy true end end end end chef-11.8.2/spec/support/lib/library_load_order.rb0000644000004100000410000000061012254362222022134 0ustar www-datawww-data# Helper module to track the load order of library files. # Used by `cookbook_compiler_spec.rb` # # This module must be loaded for any tests that load the cookbook # data/run_context/cookbooks/test to succeed. module LibraryLoadOrder extend self def load_order @load_order ||= [] end def reset! @load_order = nil end def record(file) load_order << file end end chef-11.8.2/spec/support/mock/0000755000004100000410000000000012254362222016137 5ustar www-datawww-datachef-11.8.2/spec/support/mock/constant.rb0000644000004100000410000000277312254362222020326 0ustar www-datawww-data# Allows easy mocking of global and class constants # Inspired by: # http://missingbit.blogspot.com/2011/07/stubbing-constants-in-rspec_20.html # http://digitaldumptruck.jotabout.com/?p=551 def mock_constants(constants, &block) saved_constants = {} constants.each do |constant, val| source_object, const_name = parse_constant(constant) saved_constants[constant] = source_object.const_get(const_name) with_warnings(nil) {source_object.const_set(const_name, val) } end begin block.call ensure constants.each do |constant, val| source_object, const_name = parse_constant(constant) with_warnings(nil) { source_object.const_set(const_name, saved_constants[constant]) } end end end def parse_constant(constant) source, _, constant_name = constant.to_s.rpartition('::') [constantize(source), constant_name] end # Taken from ActiveSupport # File activesupport/lib/active_support/core_ext/kernel/reporting.rb, line 3 # # Sets $VERBOSE for the duration of the block and back to its original value afterwards. def with_warnings(flag) old_verbose, $VERBOSE = $VERBOSE, flag yield ensure $VERBOSE = old_verbose end # File activesupport/lib/active_support/inflector/methods.rb, line 209 def constantize(camel_cased_word) names = camel_cased_word.split('::') names.shift if names.empty? || names.first.empty? constant = Object names.each do |name| constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name) end constant end chef-11.8.2/spec/support/mock/platform.rb0000644000004100000410000000155312254362222020314 0ustar www-datawww-data# makes Chef think it's running on a certain platform..useful for unit testing # platform-specific functionality. # # If a block is given yields to the block with +RUBY_PLATFORM+ set to # 'i386-mingw32' (windows) or 'x86_64-darwin11.2.0' (unix). Usueful for # testing code that mixes in platform specific modules like +Chef::Mixin::Securable+ # or +Chef::FileAccessControl+ def platform_mock(platform = :unix, &block) Chef::Platform.stub!(:windows?).and_return(platform == :windows ? true : false) ENV['SYSTEMDRIVE'] = (platform == :windows ? 'C:' : nil) if block_given? mock_constants({"RUBY_PLATFORM" => (platform == :windows ? 'i386-mingw32' : 'x86_64-darwin11.2.0'), "File::PATH_SEPARATOR" => (platform == :windows ? ";" : ":"), "File::ALT_SEPARATOR" => (platform == :windows ? "\\" : nil) }) do yield end end end chef-11.8.2/spec/support/matchers/0000755000004100000410000000000012254362222017014 5ustar www-datawww-datachef-11.8.2/spec/support/matchers/leak.rb0000644000004100000410000000471612254362222020265 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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 Matchers module LeakBase include RSpec::Matchers def initialize(opts={}, &block) @warmup = opts[:warmup] || 5 @iterations = opts[:iterations] || 100 @variance = opts[:variance] || 1000 end def failure_message_for_should "expected final measure [#{@final_measure}] to be greater than or within +/- #{@variance} delta of initial measure [#{@initial_measure}]" end def failure_message_for_should_not "expected final measure [#{@final_measure}] to be less than or within +/- #{@variance} delta of initial measure [#{@initial_measure}]" end private def match(measure, given_proc) profiler.start @initial_measure = 0 @final_measure = 0 @warmup.times do given_proc.call end @initial_measure = profiler.send(measure) @iterations.times do given_proc.call end profiler.stop @final_measure = profiler.send(measure) @final_measure > (@initial_measure + @variance) end def profiler @profiler ||= begin if Chef::Platform.windows? require File.join(File.dirname(__FILE__), '..', 'platforms', 'prof', 'win32') RSpec::Prof::Win32::Profiler.new else require File.join(File.dirname(__FILE__), '..', 'prof', 'gc') RSpec::Prof::GC::Profiler.new end end end end class LeakMemory include LeakBase def matches?(given_proc) match(:working_set_size, given_proc) end end class LeakHandles include LeakBase def matches?(given_proc) match(:handle_count, given_proc) end end def leak_memory(opts, &block) Matchers::LeakMemory.new(opts, &block) end def leak_handles(opts, &block) Matchers::LeakHandles.new(opts, &block) end end chef-11.8.2/spec/support/shared/0000755000004100000410000000000012254362222016454 5ustar www-datawww-datachef-11.8.2/spec/support/shared/integration/0000755000004100000410000000000012254362222020777 5ustar www-datawww-datachef-11.8.2/spec/support/shared/integration/knife_support.rb0000644000004100000410000001257312254362222024224 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'chef/config' require 'chef/knife' require 'chef/application/knife' require 'logger' require 'chef/log' module KnifeSupport DEBUG = ENV['DEBUG'] def knife(*args, &block) # Allow knife('role from file roles/blah.json') rather than requiring the # arguments to be split like knife('role', 'from', 'file', 'roles/blah.json') # If any argument will have actual spaces in it, the long form is required. # (Since knife commands always start with the command name, and command # names with spaces are always multiple args, this is safe.) if args.length == 1 args = args[0].split(/\s+/) end # Make output stable Chef::Config[:concurrency] = 1 # Work on machines where we can't access /var checksums_cache_dir = Dir.mktmpdir('checksums') do |checksums_cache_dir| Chef::Config[:cache_options] = { :path => checksums_cache_dir, :skip_expires => true } # This is Chef::Knife.run without load_commands--we'll load stuff # ourselves, thank you very much stdout = StringIO.new stderr = StringIO.new old_loggers = Chef::Log.loggers old_log_level = Chef::Log.level begin puts "knife: #{args.join(' ')}" if DEBUG subcommand_class = Chef::Knife.subcommand_class_from(args) subcommand_class.options = Chef::Application::Knife.options.merge(subcommand_class.options) subcommand_class.load_deps instance = subcommand_class.new(args) # Capture stdout/stderr instance.ui = Chef::Knife::UI.new(stdout, stderr, STDIN, {}) # Don't print stuff Chef::Config[:verbosity] = ( DEBUG ? 2 : 0 ) instance.config[:config_file] = File.join(CHEF_SPEC_DATA, "null_config.rb") # Configure chef with a (mostly) blank knife.rb # We set a global and then mutate it in our stub knife.rb so we can be # extra sure that we're not loading someone's real knife.rb and then # running test scenarios against a real chef server. If things don't # smell right, abort. $__KNIFE_INTEGRATION_FAILSAFE_CHECK = "ole" instance.configure_chef unless $__KNIFE_INTEGRATION_FAILSAFE_CHECK == "ole ole" raise Exception, "Potential misconfiguration of integration tests detected. Aborting test." end logger = Logger.new(stderr) logger.formatter = proc { |severity, datetime, progname, msg| "#{severity}: #{msg}\n" } Chef::Log.use_log_devices([logger]) Chef::Log.level = ( DEBUG ? :debug : :warn ) Chef::Log::Formatter.show_time = false instance.run_with_pretty_exceptions(true) exit_code = 0 # This is how rspec catches exit() rescue SystemExit => e exit_code = e.status ensure Chef::Log.use_log_devices(old_loggers) Chef::Log.level = old_log_level Chef::Config.delete(:cache_options) Chef::Config.delete(:concurrency) end KnifeResult.new(stdout.string, stderr.string, exit_code) end end private class KnifeResult def initialize(stdout, stderr, exit_code) @stdout = stdout @stderr = stderr @exit_code = exit_code end attr_reader :stdout attr_reader :stderr attr_reader :exit_code def should_fail(*args) expected = {} args.each do |arg| if arg.is_a?(Hash) expected.merge!(arg) elsif arg.is_a?(Integer) expected[:exit_code] = arg else expected[:stderr] = arg end end expected[:exit_code] = 1 if !expected[:exit_code] should_result_in(expected) end def should_succeed(*args) expected = {} args.each do |arg| if arg.is_a?(Hash) expected.merge!(arg) else expected[:stdout] = arg end end should_result_in(expected) end private def should_result_in(expected) expected[:stdout] = '' if !expected[:stdout] expected[:stderr] = '' if !expected[:stderr] expected[:exit_code] = 0 if !expected[:exit_code] # TODO make this go away stderr_actual = @stderr.sub(/^WARNING: No knife configuration file found\n/, '') if expected[:stderr].is_a?(Regexp) stderr_actual.should =~ expected[:stderr] else stderr_actual.should == expected[:stderr] end stdout_actual = @stdout if Chef::Platform.windows? stderr_actual = stderr_actual.gsub("\r\n", "\n") stdout_actual = stdout_actual.gsub("\r\n", "\n") end @exit_code.should == expected[:exit_code] if expected[:stdout].is_a?(Regexp) stdout_actual.should =~ expected[:stdout] else stdout_actual.should == expected[:stdout] end end end end chef-11.8.2/spec/support/shared/integration/integration_helper.rb0000644000004100000410000001076312254362222025215 0ustar www-datawww-data# # Author:: John Keiser () # Author:: Ho-Sheng Hsiao () # Copyright:: Copyright (c) 2012, 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'tmpdir' require 'fileutils' require 'chef/config' require 'chef_zero/rspec' require 'json' require 'support/shared/integration/knife_support' require 'spec_helper' module IntegrationSupport include ChefZero::RSpec def when_the_repository(description, *args, &block) context "When the local repository #{description}", *args do before :each do raise "Can only create one directory per test" if @repository_dir @repository_dir = Dir.mktmpdir('chef_repo') Chef::Config.chef_repo_path = @repository_dir %w(client cookbook data_bag environment node role user).each do |object_name| Chef::Config.delete("#{object_name}_path".to_sym) end end after :each do if @repository_dir begin %w(client cookbook data_bag environment node role user).each do |object_name| Chef::Config.delete("#{object_name}_path".to_sym) end Chef::Config.delete(:chef_repo_path) FileUtils.remove_entry_secure(@repository_dir) ensure @repository_dir = nil end end end def directory(relative_path, &block) old_parent_path = @parent_path @parent_path = path_to(relative_path) FileUtils.mkdir_p(@parent_path) instance_eval(&block) if block @parent_path = old_parent_path end def file(relative_path, contents) filename = path_to(relative_path) dir = File.dirname(filename) FileUtils.mkdir_p(dir) unless dir == '.' File.open(filename, 'w') do |file| raw = case contents when Hash JSON.pretty_generate(contents) when Array contents.join("\n") else contents end file.write(raw) end end def symlink(relative_path, relative_dest) filename = path_to(relative_path) dir = File.dirname(filename) FileUtils.mkdir_p(dir) unless dir == '.' dest_filename = path_to(relative_dest) File.symlink(dest_filename, filename) end def path_to(relative_path) File.expand_path(relative_path, (@parent_path || @repository_dir)) end def self.path_to(relative_path) File.expand_path(relative_path, (@parent_path || @repository_dir)) end def self.directory(relative_path, &block) before :each do directory(relative_path, &block) end end def self.file(relative_path, contents) before :each do file(relative_path, contents) end end def self.symlink(relative_path, relative_dest) before :each do symlink(relative_path, relative_dest) end end def self.cwd(relative_path) before :each do @old_cwd = Dir.pwd Dir.chdir(path_to(relative_path)) end after :each do Dir.chdir(@old_cwd) end end instance_eval(&block) end end # Versioned cookbooks def with_versioned_cookbooks(_metadata = {}, &block) _m = { :versioned_cookbooks => true }.merge(_metadata) context 'with versioned cookbooks', _m do before(:each) { Chef::Config[:versioned_cookbooks] = true } after(:each) { Chef::Config.delete(:versioned_cookbooks) } instance_eval(&block) end end def without_versioned_cookbooks(_metadata = {}, &block) _m = { :versioned_cookbooks => false }.merge(_metadata) context 'with versioned cookbooks', _m do # Just make sure this goes back to default before(:each) { Chef::Config[:versioned_cookbooks] = false } after(:each) { Chef::Config.delete(:versioned_cookbooks) } instance_eval(&block) end end end chef-11.8.2/spec/support/shared/unit/0000755000004100000410000000000012254362222017433 5ustar www-datawww-datachef-11.8.2/spec/support/shared/unit/windows_script_resource.rb0000644000004100000410000000256612254362222024756 0ustar www-datawww-data# # Author:: Adam Edwards () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'support/shared/unit/execute_resource' require 'support/shared/unit/script_resource' shared_examples_for "a Windows script resource" do before(:each) do node = Chef::Node.new node.default["kernel"] = Hash.new node.default["kernel"][:machine] = :x86_64.to_s run_context = Chef::RunContext.new(node, nil, nil) @resource = resource_instance end it "should be a kind of Chef::Resource::WindowsScript" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::WindowsScript) end context "script" do let(:script_resource) { resource_instance } it_should_behave_like "a script resource" end end chef-11.8.2/spec/support/shared/unit/api_error_inspector.rb0000644000004100000410000001470512254362222024037 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # # == API Error Inspector Examples # These tests are work in progress. They exercise the code enough to ensure it # runs without error, but don't make assertions about the output. This is # because aspects such as how information gets formatted, what's included, etc. # are still in flux. When testing an inspector, change the outputter to use # STDOUT and manually check the ouput. shared_examples_for "an api error inspector" do before do @node_name = "test-node.example.com" @config = { :validation_client_name => "testorg-validator", :validation_key => "/etc/chef/testorg-validator.pem", :chef_server_url => "https://chef-api.example.com", :node_name => "testnode-name", :client_key => "/etc/chef/client.pem" } @description = Chef::Formatters::ErrorDescription.new("Error registering the node:") @outputter = Chef::Formatters::Outputter.new(StringIO.new, STDERR) #@outputter = Chef::Formatters::Outputter.new(STDOUT, STDERR) end describe "when explaining a network error" do before do @exception = Errno::ECONNREFUSED.new("connection refused") @inspector = described_class.new(@node_name, @exception, @config) @inspector.add_explanation(@description) end it "prints a nice message" do @description.display(@outputter) end end describe "when explaining a 'private key missing' error" do before do @exception = Chef::Exceptions::PrivateKeyMissing.new("no private key yo") @inspector = described_class.new(@node_name, @exception, @config) @inspector.add_explanation(@description) end it "prints a nice message" do @description.display(@outputter) end end describe "when explaining a 401 caused by clock skew" do before do @response_body = "synchronize the clock on your host" @response = Net::HTTPUnauthorized.new("1.1", "401", "(response) unauthorized") @response.stub!(:body).and_return(@response_body) @exception = Net::HTTPServerException.new("(exception) unauthorized", @response) @inspector = described_class.new(@node_name, @exception, @config) @inspector.add_explanation(@description) end it "prints a nice message" do @description.display(@outputter) end end describe "when explaining a 401 (no clock skew)" do before do @response_body = "check your key and node name" @response = Net::HTTPUnauthorized.new("1.1", "401", "(response) unauthorized") @response.stub!(:body).and_return(@response_body) @exception = Net::HTTPServerException.new("(exception) unauthorized", @response) @inspector = described_class.new(@node_name, @exception, @config) @inspector.add_explanation(@description) end it "prints a nice message" do @description.display(@outputter) end end describe "when explaining a 403" do before do @response_body = "forbidden" @response = Net::HTTPForbidden.new("1.1", "403", "(response) forbidden") @response.stub!(:body).and_return(@response_body) @exception = Net::HTTPServerException.new("(exception) forbidden", @response) @inspector = described_class.new(@node_name, @exception, @config) @inspector.add_explanation(@description) end it "prints a nice message" do @description.display(@outputter) end end describe "when explaining a 400" do before do @response_body = "didn't like your data" @response = Net::HTTPBadRequest.new("1.1", "400", "(response) bad request") @response.stub!(:body).and_return(@response_body) @exception = Net::HTTPServerException.new("(exception) bad request", @response) @inspector = described_class.new(@node_name, @exception, @config) @inspector.add_explanation(@description) end it "prints a nice message" do @description.display(@outputter) end end describe "when explaining a 404" do before do @response_body = "probably caused by a redirect to a get" @response = Net::HTTPNotFound.new("1.1", "404", "(response) not found") @response.stub!(:body).and_return(@response_body) @exception = Net::HTTPServerException.new("(exception) not found", @response) @inspector = described_class.new(@node_name, @exception, @config) @inspector.add_explanation(@description) end it "prints a nice message" do @description.display(@outputter) end end describe "when explaining a 500" do before do @response_body = "sad trombone" @response = Net::HTTPInternalServerError.new("1.1", "500", "(response) internal server error") @response.stub!(:body).and_return(@response_body) @exception = Net::HTTPFatalError.new("(exception) internal server error", @response) @inspector = described_class.new(@node_name, @exception, @config) @inspector.add_explanation(@description) end it "prints a nice message" do @description.display(@outputter) end end describe "when explaining a 503" do before do @response_body = "sad trombone orchestra" @response = Net::HTTPBadGateway.new("1.1", "502", "(response) bad gateway") @response.stub!(:body).and_return(@response_body) @exception = Net::HTTPFatalError.new("(exception) bad gateway", @response) @inspector = described_class.new(@node_name, @exception, @config) @inspector.add_explanation(@description) end it "prints a nice message" do @description.display(@outputter) end end describe "when explaining an unknown error" do before do @exception = RuntimeError.new("(exception) something went wrong") @inspector = described_class.new(@node_name, @exception, @config) @inspector.add_explanation(@description) end it "prints a nice message" do @description.display(@outputter) end end end chef-11.8.2/spec/support/shared/unit/platform_introspector.rb0000644000004100000410000001444712254362222024431 0ustar www-datawww-data# # Author:: Seth Falcon () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010, 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # shared_examples_for "a platform introspector" do before(:each) do @platform_hash = {} %w{openbsd freebsd}.each do |x| @platform_hash[x] = { "default" => x, "1.2.3" => "#{x}-1.2.3" } end @platform_hash["debian"] = {["5", "6"] => "debian-5/6", "default" => "debian"} @platform_hash["default"] = "default" @platform_family_hash = { "debian" => "debian value", [:rhel, :fedora] => "redhatty value", "suse" => "suse value", :default => "default value" } end it "returns a default value when there is no known platform" do node = Hash.new platform_introspector.value_for_platform(@platform_hash).should == "default" end it "returns a default value when there is no known platform family" do platform_introspector.value_for_platform_family(@platform_family_hash).should == "default value" end it "returns a default value when the current platform doesn't match" do node.automatic_attrs[:platform] = "not-a-known-platform" platform_introspector.value_for_platform(@platform_hash).should == "default" end it "returns a default value when current platform_family doesn't match" do node.automatic_attrs[:platform_family] = "ultra-derived-linux" platform_introspector.value_for_platform_family(@platform_family_hash).should == "default value" end it "returns a value based on the current platform" do node.automatic_attrs[:platform] = "openbsd" platform_introspector.value_for_platform(@platform_hash).should == "openbsd" end it "returns a value based on the current platform family" do node.automatic_attrs[:platform_family] = "debian" platform_introspector.value_for_platform_family(@platform_family_hash).should == "debian value" end it "returns a version-specific value based on the current platform" do node.automatic_attrs[:platform] = "openbsd" node.automatic_attrs[:platform_version] = "1.2.3" platform_introspector.value_for_platform(@platform_hash).should == "openbsd-1.2.3" end it "returns a value based on the current platform if version not found" do node.automatic_attrs[:platform] = "openbsd" node.automatic_attrs[:platform_version] = "0.0.0" platform_introspector.value_for_platform(@platform_hash).should == "openbsd" end describe "when platform versions is an array" do it "returns a version-specific value based on the current platform" do node.automatic_attrs[:platform] = "debian" node.automatic_attrs[:platform_version] = "6" platform_introspector.value_for_platform(@platform_hash).should == "debian-5/6" end it "returns a value based on the current platform if version not found" do node.automatic_attrs[:platform] = "debian" node.automatic_attrs[:platform_version] = "0.0.0" platform_introspector.value_for_platform(@platform_hash).should == "debian" end end describe "when checking platform?" do it "returns true if the node is a provided platform and platforms are provided as symbols" do node.automatic_attrs[:platform] = 'ubuntu' platform_introspector.platform?([:redhat, :ubuntu]).should == true end it "returns true if the node is a provided platform and platforms are provided as strings" do node.automatic_attrs[:platform] = 'ubuntu' platform_introspector.platform?(["redhat", "ubuntu"]).should == true end it "returns false if the node is not of the provided platforms" do node.automatic_attrs[:platform] = 'ubuntu' platform_introspector.platform?(:splatlinux).should == false end end describe "when checking platform_family?" do it "returns true if the node is in a provided platform family and families are provided as symbols" do node.automatic_attrs[:platform_family] = 'debian' platform_introspector.platform_family?([:rhel, :debian]).should == true end it "returns true if the node is a provided platform and platforms are provided as strings" do node.automatic_attrs[:platform_family] = 'rhel' platform_introspector.platform_family?(["rhel", "debian"]).should == true end it "returns false if the node is not of the provided platforms" do node.automatic_attrs[:platform_family] = 'suse' platform_introspector.platform_family?(:splatlinux).should == false end it "returns false if the node is not of the provided platforms and platform_family is not set" do platform_introspector.platform_family?(:splatlinux).should == false end end # NOTE: this is a regression test for bug CHEF-1514 describe "when the value is an array" do before do @platform_hash = { "debian" => { "4.0" => [ :restart, :reload ], "default" => [ :restart, :reload, :status ] }, "ubuntu" => { "default" => [ :restart, :reload, :status ] }, "centos" => { "default" => [ :restart, :reload, :status ] }, "redhat" => { "default" => [ :restart, :reload, :status ] }, "fedora" => { "default" => [ :restart, :reload, :status ] }, "default" => { "default" => [:restart, :reload ] }} end it "returns the correct default for a given platform" do node.automatic_attrs[:platform] = "debian" node.automatic_attrs[:platform_version] = '9000' platform_introspector.value_for_platform(@platform_hash).should == [ :restart, :reload, :status ] end it "returns the correct platform+version specific value " do node.automatic_attrs[:platform] = "debian" node.automatic_attrs[:platform_version] = '4.0' platform_introspector.value_for_platform(@platform_hash).should == [:restart, :reload] end end end chef-11.8.2/spec/support/shared/unit/provider/0000755000004100000410000000000012254362222021265 5ustar www-datawww-datachef-11.8.2/spec/support/shared/unit/provider/file.rb0000644000004100000410000005411412254362222022536 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'tmpdir' if windows? require 'chef/win32/file' end # Filesystem stubs def file_symlink_class if windows? Chef::ReservedNames::Win32::File else File end end def normalized_path File.expand_path(resource_path) end def setup_normal_file File.stub!(:exists?).with(resource_path).and_return(true) File.stub!(:directory?).with(resource_path).and_return(false) File.stub!(:directory?).with(enclosing_directory).and_return(true) File.stub!(:writable?).with(resource_path).and_return(true) file_symlink_class.stub!(:symlink?).with(resource_path).and_return(false) file_symlink_class.stub!(:symlink?).with(normalized_path).and_return(false) end def setup_missing_file File.stub!(:exists?).with(resource_path).and_return(false) File.stub!(:directory?).with(resource_path).and_return(false) File.stub!(:directory?).with(enclosing_directory).and_return(true) File.stub!(:writable?).with(resource_path).and_return(false) file_symlink_class.stub!(:symlink?).with(resource_path).and_return(false) end def setup_symlink File.stub!(:exists?).with(resource_path).and_return(true) File.stub!(:directory?).with(normalized_path).and_return(false) File.stub!(:directory?).with(enclosing_directory).and_return(true) File.stub!(:writable?).with(resource_path).and_return(true) file_symlink_class.stub!(:symlink?).with(resource_path).and_return(true) file_symlink_class.stub!(:symlink?).with(normalized_path).and_return(true) end def setup_unwritable_file File.stub!(:exists?).with(resource_path).and_return(true) File.stub!(:directory?).with(resource_path).and_return(false) File.stub!(:directory?).with(enclosing_directory).and_return(true) File.stub!(:writable?).with(resource_path).and_return(false) file_symlink_class.stub!(:symlink?).with(resource_path).and_return(false) end def setup_missing_enclosing_directory File.stub!(:exists?).with(resource_path).and_return(false) File.stub!(:directory?).with(resource_path).and_return(false) File.stub!(:directory?).with(enclosing_directory).and_return(false) File.stub!(:writable?).with(resource_path).and_return(false) file_symlink_class.stub!(:symlink?).with(resource_path).and_return(false) end shared_examples_for Chef::Provider::File do it "should return a #{described_class}" do provider.should be_a_kind_of(described_class) end it "should store the resource passed to new as new_resource" do provider.new_resource.should eql(resource) end it "should store the node passed to new as node" do provider.node.should eql(node) end context "when loading the current resource" do context "when running load_current_resource and the file exists" do before do setup_normal_file provider.load_current_resource end it "should load a current resource based on the one specified at construction" do provider.current_resource.should be_a_kind_of(Chef::Resource::File) end it "the loaded current_resource name should be the same as the resource name" do provider.current_resource.name.should eql(resource.name) end it "the loaded current_resource path should be the same as the resoure path" do provider.current_resource.path.should eql(resource.path) end it "the loaded current_resource content should be nil" do provider.current_resource.content.should eql(nil) end end context "when running load_current_resource and the file does not exist" do before do setup_missing_file provider.load_current_resource end it "the current_resource should be a Chef::Resource::File" do provider.current_resource.should be_a_kind_of(Chef::Resource::File) end it "the current_resource name should be the same as the resource name" do provider.current_resource.name.should eql(resource.name) end it "the current_resource path should be the same as the resource path" do provider.current_resource.path.should eql(resource.path) end it "the loaded current_resource content should be nil" do provider.current_resource.content.should eql(nil) end end context "examining file security metadata on Unix with a file that exists" do before do # fake that we're on unix even if we're on windows Chef::Platform.stub!(:windows?).and_return(false) # mock up the filesystem to behave like unix setup_normal_file stat_struct = mock("::File.stat", :mode => 0600, :uid => 0, :gid => 0, :mtime => 10000) resource_real_path = File.realpath(resource.path) File.should_receive(:stat).with(resource_real_path).at_least(:once).and_return(stat_struct) Etc.stub!(:getgrgid).with(0).and_return(mock("Group Ent", :name => "wheel")) Etc.stub!(:getpwuid).with(0).and_return(mock("User Ent", :name => "root")) end context "when the new_resource does not specify any state" do before do provider.load_current_resource end it "should load the permissions into the current_resource" do provider.current_resource.mode.should == "0600" provider.current_resource.owner.should == "root" provider.current_resource.group.should == "wheel" end it "should not set the new_resource permissions" do provider.new_resource.group.should be_nil provider.new_resource.owner.should be_nil provider.new_resource.mode.should be_nil end end context "when the new_resource explicitly specifies resource state as numbers" do before do resource.owner(1) resource.group(1) resource.mode(0644) provider.load_current_resource end it "should load the permissions into the current_resource as numbers" do # Mode is always loaded as string for reporting purposes. provider.current_resource.mode.should == "0600" provider.current_resource.owner.should == 0 provider.current_resource.group.should == 0 end it "should not set the new_resource permissions" do provider.new_resource.group.should == 1 provider.new_resource.owner.should == 1 provider.new_resource.mode.should == 0644 end end context "when the new_resource explicitly specifies resource state as symbols" do before do resource.owner("macklemore") resource.group("seattlehiphop") resource.mode("0321") provider.load_current_resource end it "should load the permissions into the current_resource as symbols" do provider.current_resource.mode.should == "0600" provider.current_resource.owner.should == "root" provider.current_resource.group.should == "wheel" end it "should not set the new_resource permissions" do provider.new_resource.group.should == "seattlehiphop" provider.new_resource.owner.should == "macklemore" provider.new_resource.mode.should == "0321" end end end context "examining file security metadata on Unix with a file that does not exist" do before do # fake that we're on unix even if we're on windows Chef::Platform.stub!(:windows?).and_return(false) setup_missing_file end context "when the new_resource does not specify any state" do before do provider.load_current_resource end it "the current_resource permissions should be nil" do provider.current_resource.mode.should be_nil provider.current_resource.owner.should be_nil provider.current_resource.group.should be_nil end it "should not set the new_resource permissions" do provider.new_resource.group.should be_nil provider.new_resource.owner.should be_nil provider.new_resource.mode.should be_nil end end context "when the new_resource explicitly specifies resource state" do before do resource.owner(63945) resource.group(51948) resource.mode(0123) provider.load_current_resource end it "the current_resource permissions should be nil" do provider.current_resource.mode.should be_nil provider.current_resource.owner.should be_nil provider.current_resource.group.should be_nil end it "should not set the new_resource permissions" do provider.new_resource.group.should == 51948 provider.new_resource.owner.should == 63945 provider.new_resource.mode.should == 0123 end end end end context "when loading the new_resource after the run" do before do # fake that we're on unix even if we're on windows Chef::Platform.stub!(:windows?).and_return(false) # mock up the filesystem to behave like unix setup_normal_file stat_struct = mock("::File.stat", :mode => 0600, :uid => 0, :gid => 0, :mtime => 10000) resource_real_path = File.realpath(resource.path) File.stub!(:stat).with(resource_real_path).and_return(stat_struct) Etc.stub!(:getgrgid).with(0).and_return(mock("Group Ent", :name => "wheel")) Etc.stub!(:getpwuid).with(0).and_return(mock("User Ent", :name => "root")) provider.send(:load_resource_attributes_from_file, resource) end it "new_resource should record the new permission information" do provider.new_resource.group.should == "wheel" provider.new_resource.owner.should == "root" provider.new_resource.mode.should == "0600" end end context "when reporting security metadata on windows" do it "records the file owner" do pending end it "records rights for each user in the ACL" do pending end it "records deny_rights for each user in the ACL" do pending end end context "define_resource_requirements" do context "when the enclosing directory does not exist" do before { setup_missing_enclosing_directory } [:create, :create_if_missing, :touch].each do |action| context "action #{action}" do it "raises EnclosingDirectoryDoesNotExist" do lambda {provider.run_action(action)}.should raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist) end it "does not raise an exception in why-run mode" do Chef::Config[:why_run] = true lambda {provider.run_action(action)}.should_not raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist) Chef::Config[:why_run] = false end end end end context "when the file exists but is not deletable" do before { setup_unwritable_file } it "action delete raises InsufficientPermissions" do lambda {provider.run_action(:delete)}.should raise_error(Chef::Exceptions::InsufficientPermissions) end it "action delete also raises InsufficientPermissions in why-run mode" do Chef::Config[:why_run] = true lambda {provider.run_action(:delete)}.should raise_error(Chef::Exceptions::InsufficientPermissions) Chef::Config[:why_run] = false end end end context "action create" do it "should create the file, update its contents and then set the acls on the file" do setup_missing_file provider.should_receive(:do_create_file) provider.should_receive(:do_contents_changes) provider.should_receive(:do_acl_changes) provider.should_receive(:load_resource_attributes_from_file) provider.run_action(:create) end context "do_create_file" do context "when the file exists" do before { setup_normal_file } it "should not create the file" do provider.deployment_strategy.should_not_receive(:create).with(resource_path) provider.send(:do_create_file) provider.send(:file_created?).should == false end end context "when the file does not exist" do before { setup_missing_file } it "should create the file" do provider.deployment_strategy.should_receive(:create).with(resource_path) provider.send(:do_create_file) provider.send(:file_created?).should == true end end end context "do_contents_changes" do context "when there is content to deploy" do before do setup_normal_file provider.load_current_resource tempfile = double('Tempfile', :path => "/tmp/foo-bar-baz") content.stub!(:tempfile).and_return(tempfile) File.should_receive(:exists?).with("/tmp/foo-bar-baz").and_return(true) tempfile.should_receive(:unlink).once end context "when the contents have changed" do let(:tempfile_path) { "/tmp/foo-bar-baz" } let(:tempfile_sha256) { "42971f0ddce0cb20cf7660a123ffa1a1543beb2f1e7cd9d65858764a27f3201d" } let(:diff_for_reporting) { "+++\n---\n+foo\n-bar\n" } before do provider.stub!(:contents_changed?).and_return(true) diff = double('Diff', :for_output => ['+++','---','+foo','-bar'], :for_reporting => diff_for_reporting ) diff.stub!(:diff).with(resource_path, tempfile_path).and_return(true) provider.should_receive(:diff).at_least(:once).and_return(diff) provider.should_receive(:checksum).with(tempfile_path).and_return(tempfile_sha256) provider.should_receive(:checksum).with(resource_path).and_return(tempfile_sha256) provider.deployment_strategy.should_receive(:deploy).with(tempfile_path, normalized_path) end context "when the file was created" do before { provider.should_receive(:file_created?).at_least(:once).and_return(true) } it "does not backup the file and does not produce a diff for reporting" do provider.should_not_receive(:do_backup) provider.send(:do_contents_changes) resource.diff.should be_nil end end context "when the file was not created" do before { provider.should_receive(:file_created?).at_least(:once).and_return(false) } it "backs up the file and produces a diff for reporting" do provider.should_receive(:do_backup) provider.send(:do_contents_changes) resource.diff.should == diff_for_reporting end end end it "does nothing when the contents have not changed" do provider.stub!(:contents_changed?).and_return(false) provider.should_not_receive(:diff) provider.send(:do_contents_changes) end end it "does nothing when there is no content to deploy (tempfile returned from contents is nil)" do provider.send(:content).should_receive(:tempfile).at_least(:once).and_return(nil) provider.should_not_receive(:diff) lambda{ provider.send(:do_contents_changes) }.should_not raise_error end it "raises an exception when the content object returns a tempfile with a nil path" do tempfile = double('Tempfile', :path => nil) provider.send(:content).should_receive(:tempfile).at_least(:once).and_return(tempfile) lambda{ provider.send(:do_contents_changes) }.should raise_error end it "raises an exception when the content object returns a tempfile that does not exist" do tempfile = double('Tempfile', :path => "/tmp/foo-bar-baz") provider.send(:content).should_receive(:tempfile).at_least(:once).and_return(tempfile) File.should_receive(:exists?).with("/tmp/foo-bar-baz").and_return(false) lambda{ provider.send(:do_contents_changes) }.should raise_error end end context "do_acl_changes" do it "needs tests" do pending end end context "do_selinux" do context "when resource is updated" do before do setup_normal_file provider.load_current_resource provider.stub!(:resource_updated?).and_return(true) end it "should check for selinux_enabled? by default" do provider.should_receive(:selinux_enabled?) provider.send(:do_selinux) end context "when selinux fixup is enabled in the config" do before do @original_selinux_fixup = Chef::Config[:enable_selinux_file_permission_fixup] Chef::Config[:enable_selinux_file_permission_fixup] = true end after do Chef::Config[:enable_selinux_file_permission_fixup] = @original_selinux_fixup end context "when selinux is enabled on the system" do before do provider.should_receive(:selinux_enabled?).and_return(true) end it "restores security context on the file" do provider.should_receive(:restore_security_context).with(normalized_path, false) provider.send(:do_selinux) end it "restores security context recursively when told so" do provider.should_receive(:restore_security_context).with(normalized_path, true) provider.send(:do_selinux, true) end end context "when selinux is disabled on the system" do before do provider.should_receive(:selinux_enabled?).and_return(false) end it "should not restore security context" do provider.should_not_receive(:restore_security_context) provider.send(:do_selinux) end end end context "when selinux fixup is disabled in the config" do before do @original_selinux_fixup = Chef::Config[:enable_selinux_file_permission_fixup] Chef::Config[:enable_selinux_file_permission_fixup] = false end after do Chef::Config[:enable_selinux_file_permission_fixup] = @original_selinux_fixup end it "should not check for selinux_enabled?" do provider.should_not_receive(:selinux_enabled?) provider.send(:do_selinux) end end end context "when resource is not updated" do before do provider.stub!(:resource_updated?).and_return(false) end it "should not check for selinux_enabled?" do provider.should_not_receive(:selinux_enabled?) provider.send(:do_selinux) end end end end context "action delete" do context "when the file exists" do context "when the file is writable" do context "when the file is not a symlink" do before { setup_normal_file } it "should backup and delete the file and be updated by the last action" do provider.should_receive(:do_backup).at_least(:once).and_return(true) File.should_receive(:delete).with(resource_path).and_return(true) provider.run_action(:delete) resource.should be_updated_by_last_action end end context "when the file is a symlink" do before { setup_symlink } it "should not backup the symlink" do provider.should_not_receive(:do_backup) File.should_receive(:delete).with(resource_path).and_return(true) provider.run_action(:delete) resource.should be_updated_by_last_action end end end context "when the file is not writable" do before { setup_unwritable_file } it "should not try to backup or delete the file, and should not be updated by last action" do provider.should_not_receive(:do_backup) File.should_not_receive(:delete) lambda { provider.run_action(:delete) }.should raise_error() resource.should_not be_updated_by_last_action end end end context "when the file does not exist" do before { setup_missing_file } it "should not try to backup or delete the file, and should not be updated by last action" do provider.should_not_receive(:do_backup) File.should_not_receive(:delete) lambda { provider.run_action(:delete) }.should_not raise_error() resource.should_not be_updated_by_last_action end end end context "action touch" do context "when the file does not exist" do before { setup_missing_file } it "should update the atime/mtime on action_touch" do File.should_receive(:utime).once provider.should_receive(:action_create) provider.run_action(:touch) resource.should be_updated_by_last_action end end context "when the file exists" do before { setup_normal_file } it "should update the atime/mtime on action_touch" do File.should_receive(:utime).once provider.should_receive(:action_create) provider.run_action(:touch) resource.should be_updated_by_last_action end end end context "action create_if_missing" do context "when the file does not exist" do before { setup_missing_file } it "should call action_create" do provider.should_receive(:action_create) provider.run_action(:create_if_missing) end end context "when the file exists" do before { setup_normal_file } it "should not call action_create" do provider.should_not_receive(:action_create) provider.run_action(:create_if_missing) end end end end chef-11.8.2/spec/support/shared/unit/provider/useradd_based_user_provider.rb0000644000004100000410000003724612254362222027363 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008, 2010, 2013 Opscode, Inc. # # License:: Apache License, Version 2.0 # # 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. # shared_examples_for "a useradd-based user provider" do |supported_useradd_options| before(:each) do @node = Chef::Node.new @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::User.new("adam", @run_context) @new_resource.comment "Adam Jacob" @new_resource.uid 1000 @new_resource.gid 1000 @new_resource.home "/home/adam" @new_resource.shell "/usr/bin/zsh" @new_resource.password "abracadabra" @new_resource.system false @new_resource.manage_home false @new_resource.non_unique false @current_resource = Chef::Resource::User.new("adam", @run_context) @current_resource.comment "Adam Jacob" @current_resource.uid 1000 @current_resource.gid 1000 @current_resource.home "/home/adam" @current_resource.shell "/usr/bin/zsh" @current_resource.password "abracadabra" @current_resource.system false @current_resource.manage_home false @current_resource.non_unique false @current_resource.supports({:manage_home => false, :non_unique => false}) end describe "when setting option" do supported_useradd_options.each do |attribute, option| it "should check for differences in #{attribute} between the new and current resources" do @current_resource.should_receive(attribute) @new_resource.should_receive(attribute) provider.universal_options end it "should set the option for #{attribute} if the new resources #{attribute} is not nil" do @new_resource.stub!(attribute).and_return("hola") provider.universal_options.should eql([option, 'hola']) end it "should set the option for #{attribute} if the new resources #{attribute} is not nil, without homedir management" do @new_resource.stub!(:supports).and_return({:manage_home => false, :non_unique => false}) @new_resource.stub!(attribute).and_return("hola") provider.universal_options.should eql([option, 'hola']) end it "should set the option for #{attribute} if the new resources #{attribute} is not nil, without homedir management (using real attributes)" do @new_resource.stub!(:manage_home).and_return(false) @new_resource.stub!(:non_unique).and_return(false) @new_resource.stub!(attribute).and_return("hola") provider.universal_options.should eql([option, 'hola']) end end it "should combine all the possible options" do combined_opts = [] supported_useradd_options.sort{ |a,b| a[0] <=> b[0] }.each do |attribute, option| @new_resource.stub!(attribute).and_return("hola") combined_opts << option << 'hola' end provider.universal_options.should eql(combined_opts) end describe "when we want to create a system user" do before do @new_resource.manage_home(true) @new_resource.non_unique(false) end it "should set useradd -r" do @new_resource.system(true) provider.useradd_options.should == [ "-r" ] end end describe "when the resource has a different home directory and supports home directory management" do before do @new_resource.stub!(:home).and_return("/wowaweea") @new_resource.stub!(:supports).and_return({:manage_home => true, :non_unique => false}) end it "should set -m -d /homedir" do provider.universal_options.should == %w[-d /wowaweea -m] provider.useradd_options.should == [] end end describe "when the resource has a different home directory and supports home directory management (using real attributes)" do before do @new_resource.stub!(:home).and_return("/wowaweea") @new_resource.stub!(:manage_home).and_return(true) @new_resource.stub!(:non_unique).and_return(false) end it "should set -m -d /homedir" do provider.universal_options.should eql(%w[-d /wowaweea -m]) provider.useradd_options.should == [] end end describe "when the resource supports non_unique ids" do before do @new_resource.stub!(:supports).and_return({:manage_home => false, :non_unique => true}) end it "should set -m -o" do provider.universal_options.should eql([ "-o" ]) end end describe "when the resource supports non_unique ids (using real attributes)" do before do @new_resource.stub!(:manage_home).and_return(false) @new_resource.stub!(:non_unique).and_return(true) end it "should set -m -o" do provider.universal_options.should eql([ "-o" ]) end end end describe "when creating a user" do before(:each) do @current_resource = Chef::Resource::User.new(@new_resource.name, @run_context) @current_resource.username(@new_resource.username) provider.current_resource = @current_resource provider.new_resource.manage_home true provider.new_resource.home "/Users/mud" provider.new_resource.gid '23' end it "runs useradd with the computed command options" do command = ["useradd", "-c", 'Adam Jacob', "-g", '23' ] command.concat(["-p", 'abracadabra']) if supported_useradd_options.key?("password") command.concat([ "-s", '/usr/bin/zsh', "-u", '1000', "-d", '/Users/mud', "-m", "adam" ]) provider.should_receive(:shell_out!).with(*command).and_return(true) provider.create_user end describe "and home is not specified for new system user resource" do before do provider.new_resource.system true # there is no public API to set attribute's value to nil provider.new_resource.instance_variable_set("@home", nil) end it "should not include -m or -d in the command options" do command = ["useradd", "-c", 'Adam Jacob', "-g", '23'] command.concat(["-p", 'abracadabra']) if supported_useradd_options.key?("password") command.concat([ "-s", '/usr/bin/zsh', "-u", '1000', "-r", "adam" ]) provider.should_receive(:shell_out!).with(*command).and_return(true) provider.create_user end end end describe "when managing a user" do before(:each) do provider.new_resource.manage_home true provider.new_resource.home "/Users/mud" provider.new_resource.gid '23' end # CHEF-3423, -m must come before the username # CHEF-4305, -d must come before -m to support CentOS/RHEL 5 it "runs usermod with the computed command options" do command = ["usermod", "-g", '23', "-d", '/Users/mud', "-m", "adam" ] provider.should_receive(:shell_out!).with(*command).and_return(true) provider.manage_user end it "does not set the -r option to usermod" do @new_resource.system(true) command = ["usermod", "-g", '23', "-d", '/Users/mud', "-m", "adam" ] provider.should_receive(:shell_out!).with(*command).and_return(true) provider.manage_user end it "CHEF-3429: does not set -m if we aren't changing the home directory" do provider.should_receive(:updating_home?).and_return(false) command = ["usermod", "-g", '23', "adam" ] provider.should_receive(:shell_out!).with(*command).and_return(true) provider.manage_user end end describe "when removing a user" do it "should run userdel with the new resources user name" do provider.should_receive(:shell_out!).with("userdel", @new_resource.username).and_return(true) provider.remove_user end it "should run userdel with the new resources user name and -r if manage_home is true" do @new_resource.supports({ :manage_home => true, :non_unique => false}) provider.should_receive(:shell_out!).with("userdel", "-r", @new_resource.username).and_return(true) provider.remove_user end it "should run userdel with the new resources user name if non_unique is true" do @new_resource.supports({ :manage_home => false, :non_unique => true}) provider.should_receive(:shell_out!).with("userdel", @new_resource.username).and_return(true) provider.remove_user end end describe "when checking the lock" do # lazy initialize so we can modify stdout and stderr strings let(:passwd_s_status) do mock("Mixlib::ShellOut command", :exitstatus => 0, :stdout => @stdout, :stderr => @stderr) end before(:each) do # @node = Chef::Node.new # @new_resource = mock("Chef::Resource::User", # :nil_object => true, # :username => "adam" # ) #provider = Chef::Provider::User::Useradd.new(@node, @new_resource) @stdout = "root P 09/02/2008 0 99999 7 -1" @stderr = "" end it "should return false if status begins with P" do provider.should_receive(:shell_out!). with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}). and_return(passwd_s_status) provider.check_lock.should eql(false) end it "should return false if status begins with N" do @stdout = "root N" provider.should_receive(:shell_out!). with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}). and_return(passwd_s_status) provider.check_lock.should eql(false) end it "should return true if status begins with L" do @stdout = "root L" provider.should_receive(:shell_out!). with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}). and_return(passwd_s_status) provider.check_lock.should eql(true) end it "should raise a Chef::Exceptions::User if passwd -S fails on anything other than redhat/centos" do @node.automatic_attrs[:platform] = 'ubuntu' provider.should_receive(:shell_out!). with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}). and_return(passwd_s_status) passwd_s_status.should_receive(:exitstatus).and_return(1) lambda { provider.check_lock }.should raise_error(Chef::Exceptions::User) end ['redhat', 'centos'].each do |os| it "should not raise a Chef::Exceptions::User if passwd -S exits with 1 on #{os} and the passwd package is version 0.73-1" do @node.automatic_attrs[:platform] = os passwd_s_status.should_receive(:exitstatus).and_return(1) provider.should_receive(:shell_out!). with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}). and_return(passwd_s_status) rpm_status = mock("Mixlib::ShellOut command", :exitstatus => 0, :stdout => "passwd-0.73-1\n", :stderr => "") provider.should_receive(:shell_out!).with("rpm -q passwd").and_return(rpm_status) lambda { provider.check_lock }.should_not raise_error(Chef::Exceptions::User) end it "should raise a Chef::Exceptions::User if passwd -S exits with 1 on #{os} and the passwd package is not version 0.73-1" do @node.automatic_attrs[:platform] = os passwd_s_status.should_receive(:exitstatus).and_return(1) provider.should_receive(:shell_out!). with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}). and_return(passwd_s_status) rpm_status = mock("Mixlib::ShellOut command", :exitstatus => 0, :stdout => "passwd-0.73-2\n", :stderr => "") provider.should_receive(:shell_out!).with("rpm -q passwd").and_return(rpm_status) lambda { provider.check_lock }.should raise_error(Chef::Exceptions::User) end it "should raise a ShellCommandFailed exception if passwd -S exits with something other than 0 or 1 on #{os}" do @node.automatic_attrs[:platform] = os provider.should_receive(:shell_out!).and_raise(Mixlib::ShellOut::ShellCommandFailed) lambda { provider.check_lock }.should raise_error(Mixlib::ShellOut::ShellCommandFailed) end end end describe "when locking the user" do it "should run usermod -L with the new resources username" do provider.should_receive(:shell_out!).with("usermod", "-L", @new_resource.username) provider.lock_user end end describe "when unlocking the user" do it "should run usermod -L with the new resources username" do provider.should_receive(:shell_out!).with("usermod", "-U", @new_resource.username) provider.unlock_user end end describe "when checking if home needs updating" do [ { "action" => "should return false if home matches", "current_resource_home" => [ "/home/laurent" ], "new_resource_home" => [ "/home/laurent" ], "expected_result" => false }, { "action" => "should return true if home doesn't match", "current_resource_home" => [ "/home/laurent" ], "new_resource_home" => [ "/something/else" ], "expected_result" => true }, { "action" => "should return false if home only differs by trailing slash", "current_resource_home" => [ "/home/laurent" ], "new_resource_home" => [ "/home/laurent/", "/home/laurent" ], "expected_result" => false }, { "action" => "should return false if home is an equivalent path", "current_resource_home" => [ "/home/laurent" ], "new_resource_home" => [ "/home/./laurent", "/home/laurent" ], "expected_result" => false }, ].each do |home_check| it home_check["action"] do provider.current_resource.home home_check["current_resource_home"].first @current_home_mock = mock("Pathname") provider.new_resource.home home_check["new_resource_home"].first @new_home_mock = mock("Pathname") Pathname.should_receive(:new).with(@current_resource.home).and_return(@current_home_mock) @current_home_mock.should_receive(:cleanpath).and_return(home_check["current_resource_home"].last) Pathname.should_receive(:new).with(@new_resource.home).and_return(@new_home_mock) @new_home_mock.should_receive(:cleanpath).and_return(home_check["new_resource_home"].last) provider.updating_home?.should == home_check["expected_result"] end end it "should return true if the current home does not exist but a home is specified by the new resource" do @new_resource = Chef::Resource::User.new("adam", @run_context) @current_resource = Chef::Resource::User.new("adam", @run_context) provider = Chef::Provider::User::Useradd.new(@new_resource, @run_context) provider.current_resource = @current_resource @current_resource.home nil @new_resource.home "/home/kitten" provider.updating_home?.should == true end end end chef-11.8.2/spec/support/shared/unit/script_resource.rb0000644000004100000410000000273412254362222023201 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' shared_examples_for "a script resource" do before(:each) do @resource = script_resource end it "should create a new Chef::Resource::Script" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::Script) end it "should have a resource name of :script" do @resource.resource_name.should eql(resource_name) end it "should set command to the argument provided to new" do @resource.command.should eql(resource_instance_name) end it "should accept a string for the code" do @resource.code "hey jude" @resource.code.should eql("hey jude") end it "should accept a string for the flags" do @resource.flags "-f" @resource.flags.should eql("-f") end end chef-11.8.2/spec/support/shared/unit/file_system_support.rb0000644000004100000410000000427412254362222024106 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system' require 'chef/chef_fs/file_system/memory_root' require 'chef/chef_fs/file_system/memory_dir' require 'chef/chef_fs/file_system/memory_file' module FileSystemSupport def memory_fs(pretty_name, value, cannot_be_in_regex = nil) if !value.is_a?(Hash) raise "memory_fs() must take a Hash" end dir = Chef::ChefFS::FileSystem::MemoryRoot.new(pretty_name, cannot_be_in_regex) value.each do |key, child| dir.add_child(memory_fs_value(child, key.to_s, dir)) end dir end def memory_fs_value(value, name = '', parent = nil) if value.is_a?(Hash) dir = Chef::ChefFS::FileSystem::MemoryDir.new(name, parent) value.each do |key, child| dir.add_child(memory_fs_value(child, key.to_s, dir)) end dir else Chef::ChefFS::FileSystem::MemoryFile.new(name, parent, value || "#{name}\n") end end def pattern(p) Chef::ChefFS::FilePattern.new(p) end def return_paths(*expected) ReturnPaths.new(expected) end def no_blocking_calls_allowed [ Chef::ChefFS::FileSystem::MemoryFile, Chef::ChefFS::FileSystem::MemoryDir ].each do |c| [ :children, :exists?, :read ].each do |m| c.any_instance.stub(m).and_raise("#{m.to_s} should not be called") end end end def list_should_yield_paths(fs, pattern_str, *expected_paths) result_paths = [] Chef::ChefFS::FileSystem.list(fs, pattern(pattern_str)).each { |result| result_paths << result.path } result_paths.should =~ expected_paths end end chef-11.8.2/spec/support/shared/unit/execute_resource.rb0000644000004100000410000000675712254362222023350 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' shared_examples_for "an execute resource" do before(:each) do @resource = execute_resource end it "should create a new Chef::Resource::Execute" do @resource.should be_a_kind_of(Chef::Resource) @resource.should be_a_kind_of(Chef::Resource::Execute) end it "should set the command to the first argument to new" do @resource.command.should eql(resource_instance_name) end it "should accept an array on instantiation, too" do resource = Chef::Resource::Execute.new(%w{something else}) resource.should be_a_kind_of(Chef::Resource) resource.should be_a_kind_of(Chef::Resource::Execute) resource.command.should eql(%w{something else}) end it "should accept a string for the command to run" do @resource.command "something" @resource.command.should eql("something") end it "should accept an array for the command to run" do @resource.command %w{something else} @resource.command.should eql(%w{something else}) end it "should accept a string for the cwd" do @resource.cwd "something" @resource.cwd.should eql("something") end it "should accept a hash for the environment" do test_hash = { :one => :two } @resource.environment(test_hash) @resource.environment.should eql(test_hash) end it "allows the environment to be specified with #env" do @resource.should respond_to(:env) end it "should accept a string for the group" do @resource.group "something" @resource.group.should eql("something") end it "should accept an integer for the group" do @resource.group 1 @resource.group.should eql(1) end it "should accept an array for the execution path" do @resource.path ["woot"] @resource.path.should eql(["woot"]) end it "should accept an integer for the return code" do @resource.returns 1 @resource.returns.should eql(1) end it "should accept an integer for the timeout" do @resource.timeout 1 @resource.timeout.should eql(1) end it "should accept a string for the user" do @resource.user "something" @resource.user.should eql("something") end it "should accept an integer for the user" do @resource.user 1 @resource.user.should eql(1) end it "should accept a string for creates" do @resource.creates "something" @resource.creates.should eql("something") end describe "when it has cwd, environment, group, path, return value, and a user" do before do @resource.command("grep") @resource.cwd("/tmp/") @resource.environment({ :one => :two }) @resource.group("legos") @resource.path(["/var/local/"]) @resource.returns(1) @resource.user("root") end it "returns the command as its identity" do @resource.identity.should == "grep" end end end chef-11.8.2/spec/support/shared/functional/0000755000004100000410000000000012254362222020616 5ustar www-datawww-datachef-11.8.2/spec/support/shared/functional/file_resource.rb0000644000004100000410000006543312254362222024004 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # shared_context "deploying with move" do before do Chef::Config[:file_backup_path] = CHEF_SPEC_BACKUP_PATH Chef::Config[:file_atomic_update] = true end end shared_context "deploying with copy" do before do Chef::Config[:file_backup_path] = CHEF_SPEC_BACKUP_PATH Chef::Config[:file_atomic_update] = false end end shared_context "deploying via tmpdir" do before do Chef::Config[:file_staging_uses_destdir] = false Chef::Config[:file_backup_path] = CHEF_SPEC_BACKUP_PATH end end shared_context "deploying via destdir" do before do Chef::Config[:file_staging_uses_destdir] = true Chef::Config[:file_backup_path] = CHEF_SPEC_BACKUP_PATH end end shared_examples_for "a file with the wrong content" do before do # Assert starting state is as expected File.should exist(path) # Kinda weird, in this case @expected_checksum is the cksum of the file # with incorrect content. sha256_checksum(path).should == @expected_checksum end include_context "diff disabled" context "when running action :create" do context "with backups enabled" do before do resource.run_action(:create) end it "overwrites the file with the updated content when the :create action is run" do File.stat(path).mtime.should > @expected_mtime sha256_checksum(path).should_not == @expected_checksum end it "backs up the existing file" do Dir.glob(backup_glob).size.should equal(1) end it "is marked as updated by last action" do resource.should be_updated_by_last_action end it "should restore the security contexts on selinux", :selinux_only do selinux_security_context_restored?(path).should be_true end end context "with backups disabled" do before do resource.backup(0) resource.run_action(:create) end it "should not attempt to backup the existing file if :backup == 0" do Dir.glob(backup_glob).size.should equal(0) end it "should restore the security contexts on selinux", :selinux_only do selinux_security_context_restored?(path).should be_true end end end describe "when running action :create_if_missing" do before do resource.run_action(:create_if_missing) end it "doesn't overwrite the file when the :create_if_missing action is run" do File.stat(path).mtime.should == @expected_mtime sha256_checksum(path).should == @expected_checksum end it "is not marked as updated" do resource.should_not be_updated_by_last_action end it "should restore the security contexts on selinux", :selinux_only do selinux_security_context_restored?(path).should be_true end end describe "when running action :delete" do before do resource.run_action(:delete) end it "deletes the file" do File.should_not exist(path) end it "is marked as updated by last action" do resource.should be_updated_by_last_action end end end shared_examples_for "a file with the correct content" do before do # Assert starting state is as expected File.should exist(path) sha256_checksum(path).should == @expected_checksum end include_context "diff disabled" describe "when running action :create" do before do resource.run_action(:create) end it "does not overwrite the original when the :create action is run" do sha256_checksum(path).should == @expected_checksum end it "does not update the mtime of the file when the :create action is run" do File.stat(path).mtime.should == @expected_mtime end it "is not marked as updated by last action" do resource.should_not be_updated_by_last_action end it "should restore the security contexts on selinux", :selinux_only do selinux_security_context_restored?(path).should be_true end end describe "when running action :create_if_missing" do before do resource.run_action(:create_if_missing) end it "doesn't overwrite the file when the :create_if_missing action is run" do sha256_checksum(path).should == @expected_checksum end it "is not marked as updated by last action" do resource.should_not be_updated_by_last_action end it "should restore the security contexts on selinux", :selinux_only do selinux_security_context_restored?(path).should be_true end end describe "when running action :delete" do before do resource.run_action(:delete) end it "deletes the file when the :delete action is run" do File.should_not exist(path) end it "is marked as updated by last action" do resource.should be_updated_by_last_action end end end shared_examples_for "a file resource" do describe "when deploying with :move" do include_context "deploying with move" describe "when deploying via tmpdir" do include_context "deploying via tmpdir" it_behaves_like "a configured file resource" end describe "when deploying via destdir" do include_context "deploying via destdir" it_behaves_like "a configured file resource" end end describe "when deploying with :copy" do include_context "deploying with copy" describe "when deploying via tmpdir" do include_context "deploying via tmpdir" it_behaves_like "a configured file resource" end describe "when deploying via destdir" do include_context "deploying via destdir" it_behaves_like "a configured file resource" end end describe "when running under why run" do before do Chef::Config[:why_run] = true end after do Chef::Config[:why_run] = false end context "and the resource has a path with a missing intermediate directory" do # CHEF-3978 let(:path) do File.join(test_file_dir, "intermediate_dir", make_tmpname(file_base)) end it "successfully doesn't create the file" do resource.run_action(:create) # should not raise File.should_not exist(path) end end end describe "when setting atomic_update" do it "booleans should work" do lambda {resource.atomic_update(true)}.should_not raise_error lambda {resource.atomic_update(false)}.should_not raise_error end it "anything else should raise an error" do lambda {resource.atomic_update(:copy)}.should raise_error(ArgumentError) lambda {resource.atomic_update(:move)}.should raise_error(ArgumentError) lambda {resource.atomic_update(958)}.should raise_error(ArgumentError) end end end shared_examples_for "file resource not pointing to a real file" do def symlink?(file_path) if windows? Chef::ReservedNames::Win32::File.symlink?(file_path) else File.symlink?(file_path) end end def real_file?(file_path) !symlink?(file_path) && File.file?(file_path) end describe "when force_unlink is set to true" do it ":create unlinks the target" do real_file?(path).should be_false resource.force_unlink(true) resource.run_action(:create) real_file?(path).should be_true binread(path).should == expected_content resource.should be_updated_by_last_action end end describe "when force_unlink is set to false" do it ":create raises an error" do lambda {resource.run_action(:create) }.should raise_error(Chef::Exceptions::FileTypeMismatch) end end describe "when force_unlink is not set (default)" do it ":create raises an error" do lambda {resource.run_action(:create) }.should raise_error(Chef::Exceptions::FileTypeMismatch) end end end shared_examples_for "a configured file resource" do include_context "diff disabled" before do Chef::Log.level = :info end # note the stripping of the drive letter from the tmpdir on windows let(:backup_glob) { File.join(CHEF_SPEC_BACKUP_PATH, test_file_dir.sub(/^([A-Za-z]:)/, ""), "#{file_base}*") } # Most tests update the resource, but a few do not. We need to test that the # resource is marked updated or not correctly, but the test contexts are # composed between correct/incorrect content and correct/incorrect # permissions. We override this "let" definition in the context where content # and permissions are correct. let(:expect_updated?) { true } include Chef::Mixin::ShellOut def selinux_security_context_restored?(path) @restorecon_path = which("restorecon") if @restorecon_path.nil? restorecon_test_command = "#{@restorecon_path} -n -v #{path}" cmdresult = shell_out(restorecon_test_command) # restorecon will print the required changes to stdout if any is # needed cmdresult.stdout.empty? end def binread(file) content = File.open(file, "rb") do |f| f.read end content.force_encoding(Encoding::BINARY) if "".respond_to?(:force_encoding) content end context "when the target file is a symlink", :not_supported_on_win2k3 do let(:symlink_target) { File.join(CHEF_SPEC_DATA, "file-test-target") } describe "when configured not to manage symlink's target" do before(:each) do # configure not to manage symlink source resource.manage_symlink_source(false) # create symlinks for test context FileUtils.touch(symlink_target) if windows? Chef::ReservedNames::Win32::File.symlink(symlink_target, path) else File.symlink(symlink_target, path) end end after(:each) do FileUtils.rm_rf(symlink_target) FileUtils.rm_rf(path) end describe "when symlink target has correct content" do before(:each) do File.open(symlink_target, "wb") { |f| f.print expected_content } end it_behaves_like "file resource not pointing to a real file" end describe "when symlink target has the wrong content" do before(:each) do File.open(symlink_target, "wb") { |f| f.print "This is so wrong!!!" } end after(:each) do # symlink should never be followed binread(symlink_target).should == "This is so wrong!!!" end it_behaves_like "file resource not pointing to a real file" end end # Unix-only for now. Windows behavior may differ because of how ACL # management handles symlinks. Since symlinks are rare on Windows and this # feature primarily exists to support the case where a well-known file # (e.g., resolv.conf) has been converted to a symlink, we're okay with the # discrepancy. context "when configured to manage the symlink source", :unix_only do before do resource.manage_symlink_source(true) end context "but the symlink is part of a loop" do let(:link1_path) { File.join(CHEF_SPEC_DATA, "points-to-link2") } let(:link2_path) { File.join(CHEF_SPEC_DATA, "points-to-link1") } before do # point resource at link1: resource.path(link1_path) # create symlinks for test context File.symlink(link1_path, link2_path) File.symlink(link2_path, link1_path) end after(:each) do FileUtils.rm_rf(link1_path) FileUtils.rm_rf(link2_path) end it "raises an InvalidSymlink error" do lambda { resource.run_action(:create) }.should raise_error(Chef::Exceptions::InvalidSymlink) end it "issues a warning/assumption in whyrun mode" do begin Chef::Config[:why_run] = true resource.run_action(:create) # should not raise ensure Chef::Config[:why_run] = false end end end context "but the symlink points to a nonexistent file" do let(:link_path) { File.join(CHEF_SPEC_DATA, "points-to-nothing") } let(:not_existent_source) { File.join(CHEF_SPEC_DATA, "i-am-not-here") } before do resource.path(link_path) # create symlinks for test context File.symlink(not_existent_source, link_path) FileUtils.rm_rf(not_existent_source) end after(:each) do FileUtils.rm_rf(link_path) end it "raises an InvalidSymlink error" do lambda { resource.run_action(:create) }.should raise_error(Chef::Exceptions::InvalidSymlink) end it "issues a warning/assumption in whyrun mode" do begin Chef::Config[:why_run] = true resource.run_action(:create) # should not raise ensure Chef::Config[:why_run] = false end end end context "but the symlink is points to a non-file fs entry" do let(:link_path) { File.join(CHEF_SPEC_DATA, "points-to-dir") } let(:not_a_file_path) { File.join(CHEF_SPEC_DATA, "dir-at-end-of-symlink") } before do # point resource at link1: resource.path(link_path) # create symlinks for test context File.symlink(not_a_file_path, link_path) Dir.mkdir(not_a_file_path) end after(:each) do FileUtils.rm_rf(link_path) FileUtils.rm_rf(not_a_file_path) end it "raises an InvalidSymlink error" do lambda { resource.run_action(:create) }.should raise_error(Chef::Exceptions::FileTypeMismatch) end it "issues a warning/assumption in whyrun mode" do begin Chef::Config[:why_run] = true resource.run_action(:create) # should not raise ensure Chef::Config[:why_run] = false end end end context "when the symlink source is a real file" do let(:wrong_content) { "this is the wrong content" } let(:link_path) { File.join(CHEF_SPEC_DATA, "points-to-real-file") } before do # point resource at link: resource.path(link_path) # create symlinks for test context File.symlink(path, link_path) end after(:each) do # shared examples should not change our test setup of a file resource # pointing at a symlink: resource.path.should == link_path FileUtils.rm_rf(link_path) end context "and the permissions are incorrect" do before do # Create source (real) file File.open(path, "wb") { |f| f.write(expected_content) } end include_context "setup broken permissions" include_examples "a securable resource with existing target" it "does not replace the symlink with a real file" do resource.run_action(:create) File.should be_symlink(link_path) end end context "and the content is incorrect" do before do # Create source (real) file File.open(path, "wb") { |f| f.write(wrong_content) } end it "updates the source file content" do pending end it "marks the resource as updated" do resource.run_action(:create) resource.should be_updated_by_last_action end it "does not replace the symlink with a real file" do resource.run_action(:create) File.should be_symlink(link_path) end end context "and the content and permissions are correct" do let(:expect_updated?) { false } before do # Create source (real) file File.open(path, "wb") { |f| f.write(expected_content) } end include_context "setup correct permissions" include_examples "a securable resource with existing target" end end context "when the symlink points to a symlink which points to a real file" do let(:wrong_content) { "this is the wrong content" } let(:link_to_file_path) { File.join(CHEF_SPEC_DATA, "points-to-real-file") } let(:link_to_link_path) { File.join(CHEF_SPEC_DATA, "points-to-next-link") } before do # point resource at link: resource.path(link_to_link_path) # create symlinks for test context File.symlink(path, link_to_file_path) File.symlink(link_to_file_path, link_to_link_path) # Create source (real) file File.open(path, "wb") { |f| f.write(wrong_content) } end include_context "setup broken permissions" include_examples "a securable resource with existing target" after(:each) do # shared examples should not change our test setup of a file resource # pointing at a symlink: resource.path.should == link_to_link_path FileUtils.rm_rf(link_to_file_path) FileUtils.rm_rf(link_to_link_path) end it "does not replace the symlink with a real file" do resource.run_action(:create) File.should be_symlink(link_to_link_path) File.should be_symlink(link_to_file_path) end end end end context "when the target file is a directory" do before(:each) do FileUtils.mkdir_p(path) end after(:each) do FileUtils.rm_rf(path) end it_behaves_like "file resource not pointing to a real file" end context "when the target file is a blockdev",:unix_only, :requires_root, :not_supported_on_solaris do include Chef::Mixin::ShellOut let(:path) do File.join(CHEF_SPEC_DATA, "testdev") end before(:each) do result = shell_out("mknod #{path} b 1 2") result.stderr.empty? end after(:each) do FileUtils.rm_rf(path) end it_behaves_like "file resource not pointing to a real file" end context "when the target file is a chardev",:unix_only, :requires_root, :not_supported_on_solaris do include Chef::Mixin::ShellOut let(:path) do File.join(CHEF_SPEC_DATA, "testdev") end before(:each) do result = shell_out("mknod #{path} c 1 2") result.stderr.empty? end after(:each) do FileUtils.rm_rf(path) end it_behaves_like "file resource not pointing to a real file" end context "when the target file is a pipe",:unix_only do include Chef::Mixin::ShellOut let(:path) do File.join(CHEF_SPEC_DATA, "testpipe") end before(:each) do result = shell_out("mkfifo #{path}") result.stderr.empty? end after(:each) do FileUtils.rm_rf(path) end it_behaves_like "file resource not pointing to a real file" end context "when the target file is a socket",:unix_only do require 'socket' # It turns out that the path to a socket can have at most ~104 # bytes. Therefore we are creating our sockets in tmpdir so that # they have a shorter path. let(:test_socket_dir) { File.join(Dir.tmpdir, "sockets") } before do FileUtils::mkdir_p(test_socket_dir) end after do FileUtils::rm_rf(test_socket_dir) end let(:path) do File.join(test_socket_dir, "testsocket") end before(:each) do path.bytesize.should <= 104 UNIXServer.new(path) end after(:each) do FileUtils.rm_rf(path) end it_behaves_like "file resource not pointing to a real file" end # Regression test for http://tickets.opscode.com/browse/CHEF-4082 context "when notification is configured" do describe "when path is specified with normal seperator" do before do @notified_resource = Chef::Resource.new("punk", resource.run_context) resource.notifies(:run, @notified_resource, :immediately) resource.run_action(:create) end it "should notify the other resources correctly" do resource.should be_updated_by_last_action resource.run_context.immediate_notifications(resource).length.should == 1 end end describe "when path is specified with windows seperator", :windows_only do let(:path) { File.join(test_file_dir, make_tmpname(file_base)).gsub(::File::SEPARATOR, ::File::ALT_SEPARATOR) } before do @notified_resource = Chef::Resource.new("punk", resource.run_context) resource.notifies(:run, @notified_resource, :immediately) resource.run_action(:create) end it "should notify the other resources correctly" do resource.should be_updated_by_last_action resource.run_context.immediate_notifications(resource).length.should == 1 end end end context "when the target file does not exist" do before do # Assert starting state is expected File.should_not exist(path) end describe "when running action :create" do before do resource.run_action(:create) end it "creates the file when the :create action is run" do File.should exist(path) end it "creates the file with the correct content when the :create action is run" do binread(path).should == expected_content end it "is marked as updated by last action" do resource.should be_updated_by_last_action end it "should restore the security contexts on selinux", :selinux_only do selinux_security_context_restored?(path).should be_true end end describe "when running action :create_if_missing" do before do resource.run_action(:create_if_missing) end it "creates the file with the correct content" do binread(path).should == expected_content end it "is marked as updated by last action" do resource.should be_updated_by_last_action end it "should restore the security contexts on selinux", :selinux_only do selinux_security_context_restored?(path).should be_true end end describe "when running action :delete" do before do resource.run_action(:delete) end it "deletes the file when the :delete action is run" do File.should_not exist(path) end it "is not marked updated by last action" do resource.should_not be_updated_by_last_action end end end # Set up the context for security tests def allowed_acl(sid, expected_perms) [ ACE.access_allowed(sid, expected_perms[:specific]) ] end def denied_acl(sid, expected_perms) [ ACE.access_denied(sid, expected_perms[:specific]) ] end def parent_inheritable_acls dummy_file_path = File.join(test_file_dir, "dummy_file") FileUtils.touch(dummy_file_path) dummy_desc = get_security_descriptor(dummy_file_path) FileUtils.rm_rf(dummy_file_path) dummy_desc end it_behaves_like "a securable resource without existing target" context "when the target file has the wrong content" do before(:each) do File.open(path, "wb") { |f| f.print "This is so wrong!!!" } now = Time.now.to_i File.utime(now - 9000, now - 9000, path) @expected_mtime = File.stat(path).mtime @expected_checksum = sha256_checksum(path) end describe "and the target file has the correct permissions" do include_context "setup correct permissions" it_behaves_like "a file with the wrong content" it_behaves_like "a securable resource with existing target" end context "and the target file has incorrect permissions" do include_context "setup broken permissions" it_behaves_like "a file with the wrong content" it_behaves_like "a securable resource with existing target" end end context "when the target file has the correct content" do before(:each) do File.open(path, "wb") { |f| f.print expected_content } now = Time.now.to_i File.utime(now - 9000, now - 9000, path) @expected_mtime = File.stat(path).mtime @expected_checksum = sha256_checksum(path) end describe "and the target file has the correct permissions" do # When permissions and content are correct, chef should do nothing and # the resource should not be marked updated. let(:expect_updated?) { false } include_context "setup correct permissions" it_behaves_like "a file with the correct content" it_behaves_like "a securable resource with existing target" end context "and the target file has incorrect permissions" do include_context "setup broken permissions" it_behaves_like "a file with the correct content" it_behaves_like "a securable resource with existing target" end end # Regression test for http://tickets.opscode.com/browse/CHEF-4419 context "when the path starts with '/' and target file exists", :windows_only do let(:path) do File.join(test_file_dir[2..test_file_dir.length], make_tmpname(file_base)) end before do File.open(path, "wb") { |f| f.print expected_content } now = Time.now.to_i File.utime(now - 9000, now - 9000, path) @expected_mtime = File.stat(path).mtime @expected_checksum = sha256_checksum(path) end describe ":create action should run without any updates" do before do # Assert starting state is as expected File.should exist(path) sha256_checksum(path).should == @expected_checksum resource.run_action(:create) end it "does not overwrite the original when the :create action is run" do sha256_checksum(path).should == @expected_checksum end it "does not update the mtime of the file when the :create action is run" do File.stat(path).mtime.should == @expected_mtime end it "is not marked as updated by last action" do resource.should_not be_updated_by_last_action end end end end shared_context Chef::Resource::File do if windows? require 'chef/win32/file' end # We create the files in a different directory than tmp to exercise # different file deployment strategies more completely. let(:test_file_dir) do if windows? File.join(ENV['systemdrive'], "test-dir") else File.join(CHEF_SPEC_DATA, "test-dir") end end let(:path) do File.join(test_file_dir, make_tmpname(file_base)) end before do FileUtils::mkdir_p(test_file_dir) end after(:each) do FileUtils.rm_r(path) if File.exists?(path) FileUtils.rm_r(CHEF_SPEC_BACKUP_PATH) if File.exists?(CHEF_SPEC_BACKUP_PATH) end after do FileUtils::rm_rf(test_file_dir) end end chef-11.8.2/spec/support/shared/functional/windows_script.rb0000644000004100000410000000266412254362222024231 0ustar www-datawww-data# # Author:: Serdar Sutay () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # # Shared context used by both Powershell and Batch script provider # tests. shared_context Chef::Resource::WindowsScript do before(:all) do ohai_reader = Ohai::System.new ohai_reader.require_plugin("os") ohai_reader.require_plugin("windows::platform") new_node = Chef::Node.new new_node.consume_external_attrs(ohai_reader.data,{}) events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(new_node, {}, events) end let(:script_output_path) do File.join(Dir.tmpdir, make_tmpname("windows_script_test")) end before(:each) do k File.delete(script_output_path) if File.exists?(script_output_path) end after(:each) do File.delete(script_output_path) if File.exists?(script_output_path) end end chef-11.8.2/spec/support/shared/functional/securable_resource_with_reporting.rb0000644000004100000410000003005312254362222030144 0ustar www-datawww-data ALL_EXPANDED_PERMISSIONS = ["generic read", "generic write", "generic execute", "generic all", "delete", "read permissions", "change permissions", "take ownership", "synchronize", "access system security", "read data / list directory", "write data / add file", "append data / add subdirectory", "read extended attributes", "write extended attributes", "execute / traverse", "delete child", "read attributes", "write attributes"] shared_examples_for "a securable resource with reporting" do include_context "diff disabled" let(:current_resource) do provider = resource.provider_for_action(resource.action) provider.load_current_resource provider.current_resource end # Default mode varies based on implementation. Providers that use a tempfile # will default to 0600. Providers that use File.open will default to 0666 - # umask # let(:default_mode) { ((0100666 - File.umask) & 07777).to_s(8) } describe "reading file security metadata for reporting on unix", :unix_only => true do # According to POSIX standard created files get either the # effective gid of the process or inherits the gid of the parent # directory based on file system. Since it's hard to guess what # would happen on each platform we create a dummy file and see # what the group name should be. before do FileUtils.touch(path) @expected_gid = File.stat(path).gid @expected_group_name = Etc.getgrgid(@expected_gid).name FileUtils.rm_rf(path) end context "when the target file doesn't exist" do before do resource.action(:create) end it "has empty values for file metadata in 'current_resource'" do current_resource.owner.should be_nil current_resource.group.should be_nil current_resource.mode.should be_nil end context "and no security metadata is specified in new_resource" do it "sets the metadata values on the new_resource as strings after creating" do resource.run_action(:create) # TODO: most stable way to specify? resource.owner.should == Etc.getpwuid(Process.uid).name resource.group.should == @expected_group_name resource.mode.should == "0#{default_mode}" end end context "and owner is specified with a String (username) in new_resource", :requires_root => true do # TODO/bug: duplicated from the "securable resource" tests let(:expected_user_name) { 'nobody' } before do resource.owner(expected_user_name) resource.run_action(:create) end it "sets the owner on new_resource to the username (String) of the desired owner" do resource.owner.should == expected_user_name end end context "and owner is specified with an Integer (uid) in new_resource", :requires_root => true do # TODO: duplicated from "securable resource" let(:expected_user_name) { 'nobody' } let(:expected_uid) { Etc.getpwnam(expected_user_name).uid } let(:desired_gid) { 1337 } let(:expected_gid) { 1337 } before do resource.owner(expected_uid) resource.run_action(:create) end it "sets the owner on new_resource to the uid (Integer) of the desired owner" do resource.owner.should == expected_uid end end context "and group is specified with a String (group name)", :requires_root => true do let(:expected_group_name) { Etc.getgrent.name } before do resource.group(expected_group_name) resource.run_action(:create) end it "sets the group on new_resource to the group name (String) of the group" do resource.group.should == expected_group_name end end context "and group is specified with an Integer (gid)", :requires_root => true do let(:expected_gid) { Etc.getgrent.gid } before do resource.group(expected_gid) resource.run_action(:create) end it "sets the group on new_resource to the gid (Integer)" do resource.group.should == expected_gid end end context "and mode is specified as a String" do # Need full permission for owner here or else remote directory gets # into trouble trying to manage nested directories let(:set_mode) { "0740" } let(:expected_mode) { "0740" } before do resource.mode(set_mode) resource.run_action(:create) end it "sets mode on the new_resource as a String" do resource.mode.should == expected_mode end end context "and mode is specified as an Integer" do let(:set_mode) { 00740 } let(:expected_mode) { "0740" } before do resource.mode(set_mode) resource.run_action(:create) end it "sets mode on the new resource as a String" do resource.mode.should == expected_mode end end end context "when the target file exists" do before do FileUtils.touch(resource.path) resource.action(:create) end context "and no security metadata is specified in new_resource" do it "sets the current values on current resource as strings" do # TODO: most stable way to specify? current_resource.owner.should == Etc.getpwuid(Process.uid).name current_resource.group.should == @expected_group_name current_resource.mode.should == "0#{((0100666 - File.umask) & 07777).to_s(8)}" end end context "and owner is specified with a String (username) in new_resource" do let(:expected_user_name) { Etc.getpwuid(Process.uid).name } before do resource.owner(expected_user_name) end it "sets the owner on new_resource to the username (String) of the desired owner" do current_resource.owner.should == expected_user_name end end context "and owner is specified with an Integer (uid) in new_resource" do let(:expected_uid) { Process.uid } before do resource.owner(expected_uid) end it "sets the owner on new_resource to the uid (Integer) of the desired owner" do current_resource.owner.should == expected_uid end end context "and group is specified with a String (group name)" do before do resource.group(@expected_group_name) end it "sets the group on new_resource to the group name (String) of the group" do current_resource.group.should == @expected_group_name end end context "and group is specified with an Integer (gid)" do before do resource.group(@expected_gid) end it "sets the group on new_resource to the gid (Integer)" do current_resource.group.should == @expected_gid end end context "and mode is specified as a String" do let(:default_create_mode) { (0100666 - File.umask) } let(:expected_mode) { "0#{(default_create_mode & 07777).to_s(8)}" } before do resource.mode(expected_mode) end it "sets mode on the new_resource as a String" do current_resource.mode.should == expected_mode end end context "and mode is specified as an Integer" do let(:set_mode) { (0100666 - File.umask) & 07777 } let(:expected_mode) { "0#{set_mode.to_s(8)}" } before do resource.mode(set_mode) end it "sets mode on the new resource as a String" do current_resource.mode.should == expected_mode end end end end describe "reading file security metadata for reporting on windows", :windows_only do before do pending "windows reporting not yet fully supported" end context "when the target file doesn't exist" do # Windows reporting data should look like this (+/- ish): # { "owner" => "bob", "checksum" => "ffff", "access control" => { "bob" => { "permissions" => ["perm1", "perm2", ...], "flags" => [] }}} before do resource.action(:create) end it "has empty values for file metadata in 'current_resource'" do current_resource.owner.should be_nil current_resource.expanded_rights.should be_nil end context "and no security metadata is specified in new_resource" do it "sets the metadata values on the new_resource as strings after creating" do resource.run_action(:create) # TODO: most stable way to specify? resource.owner.should == etc.getpwuid(process.uid).name resource.state[:expanded_rights].should == { "CURRENTUSER" => { "permissions" => ALL_EXPANDED_PERMISSIONS, "flags" => [] }} resource.state[:expanded_deny_rights].should == {} resource.state[:inherits].should be_true end end context "and owner is specified with a string (username) in new_resource" do # TODO/bug: duplicated from the "securable resource" tests let(:expected_user_name) { 'Guest' } before do resource.owner(expected_user_name) resource.run_action(:create) end it "sets the owner on new_resource to the username (string) of the desired owner" do resource.owner.should == expected_user_name end end context "and owner is specified with a fully qualified domain user" do # TODO: duplicated from "securable resource" let(:expected_user_name) { 'domain\user' } before do resource.owner(expected_user_name) resource.run_action(:create) end it "sets the owner on new_resource to the fully qualified name of the desired owner" do resource.owner.should == expected_user_name end end end context "when the target file exists" do before do FileUtils.touch(resource.path) resource.action(:create) end context "and no security metadata is specified in new_resource" do it "sets the current values on current resource as strings" do # TODO: most stable way to specify? current_resource.owner.should == etc.getpwuid(process.uid).name current_resource.expanded_rights.should == { "CURRENTUSER" => ALL_EXPANDED_PERMISSIONS } end end context "and owner is specified with a string (username) in new_resource" do let(:expected_user_name) { etc.getpwuid(process.uid).name } before do resource.owner(expected_user_name) end it "sets the owner on current_resource to the username (string) of the desired owner" do current_resource.owner.should == expected_user_name end end context "and owner is specified as a fully qualified 'domain\\user' in new_resource" do let(:expected_user_name) { 'domain\user' } before do resource.owner(expected_user_name) end it "sets the owner on current_resource to the fully qualified name of the desired owner" do current_resource.owner.should == expected_uid end end context "and access rights are specified on the new_resource" do # TODO: before do blah it "sets the expanded_rights on the current resource" do pending end end context "and no access rights are specified on the current resource" do # TODO: before do blah it "sets the expanded rights on the current resource" do pending end end end end end chef-11.8.2/spec/support/shared/functional/securable_resource.rb0000644000004100000410000004240512254362222025024 0ustar www-datawww-data# # Author:: Seth Chisamore () # Author:: Mark Mzyk () # Author:: John Keiser () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'etc' shared_context "setup correct permissions" do if windows? include_context "use Windows permissions" end # I could not get this to work with :requires_unprivileged_user for whatever # reason. The setup when running as root is the same as non-root, except we # also do a chown, so this sets up correct context for either case. before :each, :unix_only do File.chmod(0776, path) now = Time.now.to_i File.utime(now - 9000, now - 9000, path) end # Root only context. before :each, :unix_only, :requires_root do File.chown(Etc.getpwnam('nobody').uid, 1337, path) end before :each, :windows_only do so = SecurableObject.new(path) so.owner = SID.Administrator so.group = SID.Administrators dacl = ACL.create(denied_acl(SID.Guest, expected_modify_perms) + allowed_acl(SID.Guest, expected_read_perms)) so.dacl = dacl end end shared_context "setup broken permissions" do if windows? include_context "use Windows permissions" end before :each, :unix_only do File.chmod(0644, path) end before :each, :unix_only, :requires_root do File.chown(0, 0, path) end before :each, :windows_only do so = SecurableObject.new(path) so.owner = SID.Guest so.group = SID.Everyone dacl = ACL.create(allowed_acl(SID.Guest, expected_modify_perms)) so.set_dacl(dacl, true) end end shared_context "use Windows permissions", :windows_only do if windows? SID ||= Chef::ReservedNames::Win32::Security::SID ACE ||= Chef::ReservedNames::Win32::Security::ACE ACL ||= Chef::ReservedNames::Win32::Security::ACL SecurableObject ||= Chef::ReservedNames::Win32::Security::SecurableObject end def get_security_descriptor(path) Chef::ReservedNames::Win32::Security.get_named_security_info(path) end def explicit_aces descriptor.dacl.select { |ace| ace.explicit? } end def extract_ace_properties(aces) hashes = [] aces.each do |ace| hashes << { :mask => ace.mask, :type => ace.type, :flags => ace.flags } end hashes end # Standard expected rights let(:expected_read_perms) do { :generic => Chef::ReservedNames::Win32::API::Security::GENERIC_READ, :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ, } end let(:expected_read_execute_perms) do { :generic => Chef::ReservedNames::Win32::API::Security::GENERIC_READ | Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE, :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_EXECUTE } end let(:expected_write_perms) do { :generic => Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE, :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE } end let(:expected_modify_perms) do { :generic => Chef::ReservedNames::Win32::API::Security::GENERIC_READ | Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE | Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE | Chef::ReservedNames::Win32::API::Security::DELETE, :specific => Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE | Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_EXECUTE | Chef::ReservedNames::Win32::API::Security::DELETE } end let(:expected_full_control_perms) do { :generic => Chef::ReservedNames::Win32::API::Security::GENERIC_ALL, :specific => Chef::ReservedNames::Win32::API::Security::FILE_ALL_ACCESS } end RSpec::Matchers.define :have_expected_properties do |mask, type, flags| match do |ace| ace.mask == mask ace.type == type ace.flags == flags end end def descriptor get_security_descriptor(path) end end shared_examples_for "a securable resource with existing target" do include_context "diff disabled" context "on Unix", :unix_only do let(:expected_user_name) { 'nobody' } let(:expected_uid) { Etc.getpwnam(expected_user_name).uid } let(:desired_gid) { 1337 } let(:expected_gid) { 1337 } pending "should set an owner (Rerun specs under root)", :requires_unprivileged_user => true pending "should set a group (Rerun specs under root)", :requires_unprivileged_user => true describe "when setting the owner", :requires_root do before do resource.owner expected_user_name resource.run_action(:create) end it "should set an owner" do File.lstat(path).uid.should == expected_uid end it "is marked as updated only if changes are made" do resource.updated_by_last_action?.should == expect_updated? end end describe "when setting the group", :requires_root do before do resource.group desired_gid resource.run_action(:create) end it "should set a group" do File.lstat(path).gid.should == expected_gid end it "is marked as updated only if changes are made" do resource.updated_by_last_action?.should == expect_updated? end end describe "when setting the permissions from octal given as a String" do before do @mode_string = '776' resource.mode @mode_string resource.run_action(:create) end it "should set permissions as specified" do pending('Linux does not support lchmod', :if => resource.instance_of?(Chef::Resource::Link) && !os_x? && !freebsd?) do (File.lstat(path).mode & 007777).should == (@mode_string.oct & 007777) end end it "is marked as updated only if changes are made" do resource.updated_by_last_action?.should == expect_updated? end end describe "when setting permissions from a literal octal Integer" do before do @mode_integer = 0776 resource.mode @mode_integer resource.run_action(:create) end it "should set permissions in numeric form as a ruby-interpreted octal" do pending('Linux does not support lchmod', :if => resource.instance_of?(Chef::Resource::Link) && !os_x? && !freebsd?) do (File.lstat(path).mode & 007777).should == (@mode_integer & 007777) end end it "is marked as updated only if changes are made" do resource.updated_by_last_action?.should == expect_updated? end end end context "on Windows", :windows_only do include_context "use Windows permissions" describe "when setting owner" do before do resource.owner('Administrator') resource.run_action(:create) end it "should set the owner" do descriptor.owner.should == SID.Administrator end it "is marked as updated only if changes are made" do resource.updated_by_last_action?.should == expect_updated? end end describe "when setting group" do before do resource.group('Administrators') resource.run_action(:create) end it "should set the group" do descriptor.group.should == SID.Administrators end it "is marked as updated only if changes are made" do resource.updated_by_last_action?.should == expect_updated? end end describe "when setting rights and deny_rights" do before do resource.deny_rights(:modify, 'Guest') resource.rights(:read, 'Guest') resource.run_action(:create) end it "should set the rights and deny_rights" do explicit_aces.should == denied_acl(SID.Guest, expected_modify_perms) + allowed_acl(SID.Guest, expected_read_perms) end it "is marked as updated only if changes are made" do resource.updated_by_last_action?.should == expect_updated? end end end end shared_examples_for "a securable resource without existing target" do include_context "diff disabled" context "on Unix", :unix_only do pending "if we need any securable resource tests on Unix without existing target resource." end context "on Windows", :windows_only do include_context "use Windows permissions" it "sets owner to Administrators on create if owner is not specified" do File.exist?(path).should == false resource.run_action(:create) descriptor.owner.should == SID.Administrators end it "sets owner when owner is specified" do resource.owner 'Guest' resource.run_action(:create) descriptor.owner.should == SID.Guest end it "fails to set owner when owner has invalid characters" do lambda { resource.owner 'Lance "The Nose" Glindenberry III' }.should raise_error#(Chef::Exceptions::ValidationFailed) end it "sets owner when owner is specified with a \\" do resource.owner "#{ENV['USERDOMAIN']}\\Guest" resource.run_action(:create) descriptor.owner.should == SID.Guest end it "leaves owner alone if owner is not specified and resource already exists" do # Set owner to Guest so it's not the same as the current user (which is the default on create) resource.owner 'Guest' resource.run_action(:create) descriptor.owner.should == SID.Guest new_resource = create_resource new_resource.owner.should == nil new_resource.run_action(:create) descriptor.owner.should == SID.Guest end it "sets group to None on create if group is not specified" do resource.group.should == nil File.exist?(path).should == false resource.run_action(:create) descriptor.group.should == SID.None end it "sets group when group is specified" do resource.group 'Everyone' resource.run_action(:create) descriptor.group.should == SID.Everyone end it "fails to set group when group has invalid characters" do lambda { resource.group 'Lance "The Nose" Glindenberry III' }.should raise_error(Chef::Exceptions::ValidationFailed) end it "sets group when group is specified with a \\" do pending "Need to find a group containing a backslash that is on most peoples' machines" do resource.group "#{ENV['COMPUTERNAME']}\\Administrators" resource.run_action(:create) descriptor.group.should == SID.Everyone end end it "leaves group alone if group is not specified and resource already exists" do # Set group to Everyone so it's not the default (None) resource.group 'Everyone' resource.run_action(:create) descriptor.group.should == SID.Everyone new_resource = create_resource new_resource.group.should == nil new_resource.run_action(:create) descriptor.group.should == SID.Everyone end describe "with rights and deny_rights attributes" do it "correctly sets :read rights" do resource.rights(:read, 'Guest') resource.run_action(:create) explicit_aces.should == allowed_acl(SID.Guest, expected_read_perms) end it "correctly sets :read_execute rights" do resource.rights(:read_execute, 'Guest') resource.run_action(:create) explicit_aces.should == allowed_acl(SID.Guest, expected_read_execute_perms) end it "correctly sets :write rights" do resource.rights(:write, 'Guest') resource.run_action(:create) explicit_aces.should == allowed_acl(SID.Guest, expected_write_perms) end it "correctly sets :modify rights" do resource.rights(:modify, 'Guest') resource.run_action(:create) explicit_aces.should == allowed_acl(SID.Guest, expected_modify_perms) end it "correctly sets :full_control rights" do resource.rights(:full_control, 'Guest') resource.run_action(:create) explicit_aces.should == allowed_acl(SID.Guest, expected_full_control_perms) end it "correctly sets deny_rights" do # deny is an ACE with full rights, but is a deny type ace, not an allow type resource.deny_rights(:full_control, 'Guest') resource.run_action(:create) explicit_aces.should == denied_acl(SID.Guest, expected_full_control_perms) end it "Sets multiple rights" do resource.rights(:read, 'Everyone') resource.rights(:modify, 'Guest') resource.run_action(:create) explicit_aces.should == allowed_acl(SID.Everyone, expected_read_perms) + allowed_acl(SID.Guest, expected_modify_perms) end it "Sets deny_rights ahead of rights" do resource.rights(:read, 'Everyone') resource.deny_rights(:modify, 'Guest') resource.run_action(:create) explicit_aces.should == denied_acl(SID.Guest, expected_modify_perms) + allowed_acl(SID.Everyone, expected_read_perms) end it "Sets deny_rights ahead of rights when specified in reverse order" do resource.deny_rights(:modify, 'Guest') resource.rights(:read, 'Everyone') resource.run_action(:create) explicit_aces.should == denied_acl(SID.Guest, expected_modify_perms) + allowed_acl(SID.Everyone, expected_read_perms) end end context "with a mode attribute" do if windows? Security ||= Chef::ReservedNames::Win32::API::Security end it "respects mode in string form as an octal number" do #on windows, mode cannot modify owner and/or group permissons #unless the owner and/or group as appropriate is specified resource.mode '400' resource.owner 'Guest' resource.group 'Everyone' resource.run_action(:create) explicit_aces.should == [ ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ) ] end it "respects mode in numeric form as a ruby-interpreted octal" do resource.mode 0700 resource.owner 'Guest' resource.run_action(:create) explicit_aces.should == [ ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ | Security::FILE_GENERIC_WRITE | Security::FILE_GENERIC_EXECUTE | Security::DELETE) ] end it "respects the owner, group and everyone bits of mode" do resource.mode 0754 resource.owner 'Guest' resource.group 'Administrators' resource.run_action(:create) explicit_aces.should == [ ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ | Security::FILE_GENERIC_WRITE | Security::FILE_GENERIC_EXECUTE | Security::DELETE), ACE.access_allowed(SID.Administrators, Security::FILE_GENERIC_READ | Security::FILE_GENERIC_EXECUTE), ACE.access_allowed(SID.Everyone, Security::FILE_GENERIC_READ) ] end it "respects the individual read, write and execute bits of mode" do resource.mode 0421 resource.owner 'Guest' resource.group 'Administrators' resource.run_action(:create) explicit_aces.should == [ ACE.access_allowed(SID.Guest, Security::FILE_GENERIC_READ), ACE.access_allowed(SID.Administrators, Security::FILE_GENERIC_WRITE | Security::DELETE), ACE.access_allowed(SID.Everyone, Security::FILE_GENERIC_EXECUTE) ] end it 'warns when mode tries to set owner bits but owner is not specified' do @warn = [] Chef::Log.stub!(:warn) { |msg| @warn << msg } resource.mode 0400 resource.run_action(:create) @warn.include?("Mode 400 includes bits for the owner, but owner is not specified").should be_true end it 'warns when mode tries to set group bits but group is not specified' do @warn = [] Chef::Log.stub!(:warn) { |msg| @warn << msg } resource.mode 0040 resource.run_action(:create) @warn.include?("Mode 040 includes bits for the group, but group is not specified").should be_true end end it "does not inherit aces if inherits is set to false" do # We need at least one ACE if we're creating a securable without # inheritance resource.rights(:full_control, 'Administrators') resource.inherits(false) resource.run_action(:create) descriptor.dacl.each do | ace | ace.inherited?.should == false end end it "has the inheritable acls of parent directory if no acl is specified" do File.exist?(path).should == false parent_acls = parent_inheritable_acls resource.run_action(:create) descriptor.dacl.each_with_index do |ace, index| # On Windows Server 2003 OS creates a default non-inheritable # ACL during file creation unless otherwise specified. ace.inherited?.should == true unless windows_win2k3? ace.should == parent_acls.dacl[index] end end end end chef-11.8.2/spec/support/shared/functional/knife.rb0000644000004100000410000000214212254362222022236 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: AJ Christensen () # Author:: Ho-Sheng Hsiao () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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 SpecHelpers module Knife def redefine_argv(value) Object.send(:remove_const, :ARGV) Object.send(:const_set, :ARGV, value) end def with_argv(*argv) original_argv = ARGV redefine_argv(argv.flatten) begin yield ensure redefine_argv(original_argv) end end end end chef-11.8.2/spec/support/shared/functional/diff_disabled.rb0000644000004100000410000000023512254362222023702 0ustar www-datawww-data shared_context "diff disabled" do before do Chef::Config[:diff_disabled] = true end after do Chef::Config[:diff_disabled] = false end end chef-11.8.2/spec/support/shared/functional/directory_resource.rb0000644000004100000410000001206512254362222025062 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # shared_examples_for "a directory resource" do include_context "diff disabled" let(:expect_updated?) {true} context "when the target directory does not exist" do before do # assert pre-condition File.should_not exist(path) end describe "when running action :create" do context "and the recursive option is not set" do before do resource.run_action(:create) end it "creates the directory when the :create action is run" do File.should exist(path) end it "is marked updated by last action" do resource.should be_updated_by_last_action end end context "and the recursive option is set" do before do File.should_not exist(path) resource.recursive(true) @recursive_path = File.join(path, 'red-headed-stepchild') resource.path(@recursive_path) resource.run_action(:create) end it "recursively creates required directories" do File.should exist(path) File.should exist(@recursive_path) end it "is marked updated by last action" do resource.should be_updated_by_last_action end end end # Set up the context for security tests def allowed_acl(sid, expected_perms) [ ACE.access_allowed(sid, expected_perms[:specific]), ACE.access_allowed(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::INHERIT_ONLY_ACE | Chef::ReservedNames::Win32::API::Security::CONTAINER_INHERIT_ACE | Chef::ReservedNames::Win32::API::Security::OBJECT_INHERIT_ACE)) ] end def denied_acl(sid, expected_perms) [ ACE.access_denied(sid, expected_perms[:specific]), ACE.access_denied(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::INHERIT_ONLY_ACE | Chef::ReservedNames::Win32::API::Security::CONTAINER_INHERIT_ACE | Chef::ReservedNames::Win32::API::Security::OBJECT_INHERIT_ACE)) ] end def parent_inheritable_acls dummy_directory_path = File.join(test_file_dir, "dummy_directory") dummy_directory = FileUtils.mkdir_p(dummy_directory_path) dummy_desc = get_security_descriptor(dummy_directory_path) FileUtils.rm_rf(dummy_directory_path) dummy_desc end it_behaves_like "a securable resource without existing target" end context "when the target directory exists" do before(:each) do # For resources such as remote_directory, simply creating the base # directory isn't enough to test that the system is in the desired state, # so we run the resource twice--otherwise the updated_by_last_action test # will fail. resource.dup.run_action(:create) File.should exist(path) resource.run_action(:create) end describe "when running action :create" do before do resource.run_action(:create) end it "does not re-create the directory" do File.should exist(path) end it "is not marked updated by last action" do resource.should_not be_updated_by_last_action end end describe "when running action :delete" do context "without the recursive option" do before do resource.run_action(:delete) end it "deletes the directory" do File.should_not exist(path) end it "is marked as updated by last action" do resource.should be_updated_by_last_action end end context "with the recursive option" do before do FileUtils.mkdir(File.join(path, 'red-headed-stepchild')) resource.recursive(true) resource.run_action(:delete) end it "recursively deletes directories" do File.should_not exist(path) end end end end end shared_context Chef::Resource::Directory do # We create the directory than tmp to exercise different file # deployment strategies more completely. let(:test_file_dir) do if windows? File.join(ENV['systemdrive'], "test-dir") else File.join(CHEF_SPEC_DATA, "test-dir") end end let(:path) do File.join(test_file_dir, make_tmpname(directory_base)) end before do FileUtils::mkdir_p(test_file_dir) end after do FileUtils::rm_rf(test_file_dir) end after(:each) do FileUtils.rm_r(path) if File.exists?(path) end end chef-11.8.2/spec/support/platform_helpers.rb0000644000004100000410000000350412254362222021103 0ustar www-datawww-datarequire 'fcntl' def ruby_gte_20? RUBY_VERSION.to_f >= 2.0 end def ruby_gte_19? RUBY_VERSION.to_f >= 1.9 end def ruby_20? !!(RUBY_VERSION =~ /^2.0/) end def ruby_19? !!(RUBY_VERSION =~ /^1.9/) end def ruby_18? !!(RUBY_VERSION =~ /^1.8/) end def windows? !!(RUBY_PLATFORM =~ /mswin|mingw|windows/) end def windows_win2k3? return false unless windows? require 'ruby-wmi' host = WMI::Win32_OperatingSystem.find(:first) (host.version && host.version.start_with?("5.2")) end # detects if the hardware is 64-bit (evaluates to true in "WOW64" mode in a 32-bit app on a 64-bit system) def windows64? windows? && ( ENV['PROCESSOR_ARCHITECTURE'] == 'AMD64' || ENV['PROCESSOR_ARCHITEW6432'] == 'AMD64' ) end # detects if the hardware is 32-bit def windows32? windows? && !windows64? end # def jruby? def unix? !windows? end def os_x? !!(RUBY_PLATFORM =~ /darwin/) end def solaris? !!(RUBY_PLATFORM =~ /solaris/) end def freebsd? !!(RUBY_PLATFORM =~ /freebsd/) end def aix? !!(RUBY_PLATFORM =~ /aix/) end def supports_cloexec? Fcntl.const_defined?('F_SETFD') && Fcntl.const_defined?('FD_CLOEXEC') end DEV_NULL = windows? ? 'NUL' : '/dev/null' def selinux_enabled? # This code is currently copied from lib/chef/util/selinux to make # specs independent of product. selinuxenabled_path = which("selinuxenabled") if selinuxenabled_path cmd = Mixlib::ShellOut.new(selinuxenabled_path, :returns => [0,1]) cmd_result = cmd.run_command case cmd_result.exitstatus when 1 return false when 0 return true else raise RuntimeError, "Unknown exit code from command #{selinuxenabled_path}: #{cmd.exitstatus}" end else # We assume selinux is not enabled if selinux utils are not # installed. return false end end def suse? File.exists?("/etc/SuSE-release") end chef-11.8.2/spec/functional/0000755000004100000410000000000012254362222015634 5ustar www-datawww-datachef-11.8.2/spec/functional/resource/0000755000004100000410000000000012254362222017463 5ustar www-datawww-datachef-11.8.2/spec/functional/resource/git_spec.rb0000644000004100000410000002166312254362222021615 0ustar www-datawww-data# # Author:: Seth Falcon () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/mixin/shell_out' require 'tmpdir' require 'shellwords' # Deploy relies heavily on symlinks, so it doesn't work on windows. describe Chef::Resource::Git do include Chef::Mixin::ShellOut let(:file_cache_path) { Dir.mktmpdir } # Some versions of git complains when the deploy directory is # already created. Here we intentionally don't create the deploy # directory beforehand. let(:base_dir_path) { Dir.mktmpdir } let(:deploy_directory) { File.join(base_dir_path, make_tmpname("git_base")) } let(:node) do Chef::Node.new.tap do |n| n.name "rspec-test" n.consume_external_attrs(@ohai.data, {}) end end let(:event_dispatch) { Chef::EventDispatch::Dispatcher.new } let(:run_context) { Chef::RunContext.new(node, {}, event_dispatch) } # These tests use git's bundle feature, which is a way to export an entire # git repo (or subset of commits) as a single file. # # Generally you can treat a git bundle as a regular git remote. # # See also: http://git-scm.com/2010/03/10/bundles.html # # Beware that git bundles don't behave exactly the same as real # remotes. To get closer to real remotes, we'll create a local clone # of the bundle to use as a remote for the tests. This at least # gives the expected responses for ls-remote using git version # 1.7.12.4 let(:git_bundle_repo) { File.expand_path("git_bundles/example-repo.gitbundle", CHEF_SPEC_DATA) } let(:origin_repo_dir) { Dir.mktmpdir } let(:origin_repo) { "#{origin_repo_dir}/example" } # This is the fourth version let(:v1_commit) { "bc5ec79931ae74089aeadca6edc173527613e6d9" } let(:v1_tag) { "9b73fb5e316bfaff7b822b0ccb3e1e08f9885085" } let(:rev_foo) { "ed181b3419b6f489bedab282348162a110d6d3a1" } let(:rev_testing) { "972d153654503bccec29f630c5dd369854a561e8" } let(:rev_head) { "d294fbfd05aa7709ad9a9b8ef6343b17d355bf5f"} let(:git_user_config) do <<-E [user] name = frodoTbaggins email = frodo@shire.org E end before(:each) do Chef::Log.level = :warn # silence git command live streams @old_file_cache_path = Chef::Config[:file_cache_path] shell_out!("git clone \"#{git_bundle_repo}\" example", :cwd => origin_repo_dir) File.open("#{origin_repo}/.git/config", "a+") {|f| f.print(git_user_config) } Chef::Config[:file_cache_path] = file_cache_path end after(:each) do Chef::Config[:file_cache_path] = @old_file_cache_path FileUtils.remove_entry_secure deploy_directory if File.exist?(deploy_directory) FileUtils.remove_entry_secure file_cache_path end after(:all) do FileUtils.remove_entry_secure origin_repo_dir end before(:all) do @ohai = Ohai::System.new @ohai.require_plugin("os") end context "working with pathes with special characters" do let(:path_with_spaces) { "#{origin_repo_dir}/path with spaces" } before(:each) do FileUtils.mkdir(path_with_spaces) FileUtils.cp(git_bundle_repo, path_with_spaces) end it "clones a repository with a space in the path" do Chef::Resource::Git.new(deploy_directory, run_context).tap do |r| r.repository "#{path_with_spaces}/example-repo.gitbundle" end.run_action(:sync) end end context "when deploying from an annotated tag" do let(:basic_git_resource) do Chef::Resource::Git.new(deploy_directory, run_context).tap do |r| r.repository origin_repo r.revision "v1.0.0" end end # We create a copy of the basic_git_resource so that we can run # the resource again and verify that it doesn't update. let(:copy_git_resource) do Chef::Resource::Git.new(deploy_directory, run_context).tap do |r| r.repository origin_repo r.revision "v1.0.0" end end it "checks out the revision pointed to by the tag commit, not the tag commit itself" do basic_git_resource.run_action(:sync) head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip head_rev.should == v1_commit # also verify the tag commit itself is what we expect as an extra sanity check rev = shell_out!('git rev-parse v1.0.0', :cwd => deploy_directory, :returns => [0]).stdout.strip rev.should == v1_tag end it "doesn't update if up-to-date" do # this used to fail because we didn't resolve the annotated tag # properly to the pointed to commit. basic_git_resource.run_action(:sync) head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip head_rev.should == v1_commit copy_git_resource.run_action(:sync) copy_git_resource.should_not be_updated end end context "when deploying from a SHA revision" do let(:basic_git_resource) do Chef::Resource::Git.new(deploy_directory, run_context).tap do |r| r.repository git_bundle_repo end end # We create a copy of the basic_git_resource so that we can run # the resource again and verify that it doesn't update. let(:copy_git_resource) do Chef::Resource::Git.new(deploy_directory, run_context).tap do |r| r.repository origin_repo end end it "checks out the expected revision ed18" do basic_git_resource.revision rev_foo basic_git_resource.run_action(:sync) head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip head_rev.should == rev_foo end it "doesn't update if up-to-date" do basic_git_resource.revision rev_foo basic_git_resource.run_action(:sync) head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip head_rev.should == rev_foo copy_git_resource.revision rev_foo copy_git_resource.run_action(:sync) copy_git_resource.should_not be_updated end it "checks out the expected revision 972d" do basic_git_resource.revision rev_testing basic_git_resource.run_action(:sync) head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip head_rev.should == rev_testing end end context "when deploying from a revision named 'HEAD'" do let(:basic_git_resource) do Chef::Resource::Git.new(deploy_directory, run_context).tap do |r| r.repository origin_repo r.revision 'HEAD' end end it "checks out the expected revision" do basic_git_resource.run_action(:sync) head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip head_rev.should == rev_head end end context "when deploying from the default revision" do let(:basic_git_resource) do Chef::Resource::Git.new(deploy_directory, run_context).tap do |r| r.repository origin_repo # use default end end it "checks out HEAD as the default revision" do basic_git_resource.run_action(:sync) head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip head_rev.should == rev_head end end context "when dealing with a repo with a degenerate tag named 'HEAD'" do before do shell_out!("git tag -m\"degenerate tag\" HEAD ed181b3419b6f489bedab282348162a110d6d3a1", :cwd => origin_repo) end let(:basic_git_resource) do Chef::Resource::Git.new(deploy_directory, run_context).tap do |r| r.repository origin_repo r.revision 'HEAD' end end let(:git_resource_default_rev) do Chef::Resource::Git.new(deploy_directory, run_context).tap do |r| r.repository origin_repo # use default of revision end end it "checks out the (master) HEAD revision and ignores the tag" do basic_git_resource.run_action(:sync) head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip head_rev.should == rev_head end it "checks out the (master) HEAD revision when no revision is specified (ignores tag)" do git_resource_default_rev.run_action(:sync) head_rev = shell_out!('git rev-parse HEAD', :cwd => deploy_directory, :returns => [0]).stdout.strip head_rev.should == rev_head end end end chef-11.8.2/spec/functional/resource/batch_spec.rb0000644000004100000410000000227712254362222022113 0ustar www-datawww-data# # Author:: Adam Edwards () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::WindowsScript::Batch, :windows_only do include_context Chef::Resource::WindowsScript let(:script_content) { "whoami" } let!(:resource) do Chef::Resource::WindowsScript::Batch.new("Batch resource functional test", @run_context) end describe "when the run action is invoked on Windows" do it "executes the script code" do resource.code(script_content + " > #{script_output_path}") resource.returns(0) resource.run_action(:run) end end end chef-11.8.2/spec/functional/resource/deploy_revision_spec.rb0000644000004100000410000005344112254362222024243 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'tmpdir' # Deploy relies heavily on symlinks, so it doesn't work on windows. describe Chef::Resource::DeployRevision, :unix_only => true do let(:file_cache_path) { Dir.mktmpdir } let(:deploy_directory) { Dir.mktmpdir } # By making restart or other operations write to this file, we can externally # track the order in which those operations happened. let(:observe_order_file) { Tempfile.new("deploy-resource-observe-operations") } before do Chef::Log.level = :info @old_file_cache_path = Chef::Config[:file_cache_path] Chef::Config[:file_cache_path] = file_cache_path end after do Chef::Config[:file_cache_path] = @old_file_cache_path FileUtils.remove_entry_secure deploy_directory if File.exist?(deploy_directory) FileUtils.remove_entry_secure file_cache_path observe_order_file.close FileUtils.remove_entry_secure observe_order_file.path end before(:all) do @ohai = Ohai::System.new @ohai.require_plugin("os") end let(:node) do Chef::Node.new.tap do |n| n.name "rspec-test" n.consume_external_attrs(@ohai.data, {}) end end let(:event_dispatch) { Chef::EventDispatch::Dispatcher.new } let(:run_context) { Chef::RunContext.new(node, {}, event_dispatch) } # These tests use git's bundle feature, which is a way to export an entire # git repo (or subset of commits) as a single file. # # Generally you can treat a git bundle as a regular git remote. # # See also: http://git-scm.com/2010/03/10/bundles.html let(:git_bundle_repo) { File.expand_path("git_bundles/sinatra-test-app.gitbundle", CHEF_SPEC_DATA) } let(:git_bundle_with_in_repo_callbacks) { File.expand_path("git_bundles/sinatra-test-app-with-callback-files.gitbundle", CHEF_SPEC_DATA) } let(:git_bundle_with_in_repo_symlinks) { File.expand_path("git_bundles/sinatra-test-app-with-symlinks.gitbundle", CHEF_SPEC_DATA) } # This is the fourth version let(:latest_rev) { "3eb5ca6c353c83d9179dd3b29347539829b401f3" } # This is the third version let(:previous_rev) { "6d19a6dbecc8e37f5b2277345885c0c783eb8fb1" } # This is the sixth version, it is on the "with-deploy-scripts" branch let(:rev_with_in_repo_callbacks) { "2404d015882659754bdb93ad6e4b4d3d02691a82" } # This is the fifth version in the "with-symlinks" branch let(:rev_with_in_repo_symlinks) { "5a4748c52aaea8250b4346a9b8ede95ee3755e28" } # Read values from the +observe_order_file+ and split each line. This way you # can see in which order things really happened. def actual_operations_order IO.read(observe_order_file.path).split("\n").map(&:strip) end # 1. touch `restart.txt` in cwd so we know that the command is run with the # right cwd. # 2. Append +tag+ to the `observe_order_file` so we can check the order in # which operations happen later in the test. def shell_restart_command(tag) "touch restart.txt && echo '#{tag}' >> #{observe_order_file.path}" end let(:basic_deploy_resource) do Chef::Resource::DeployRevision.new(deploy_directory, run_context).tap do |r| r.repo git_bundle_repo r.symlink_before_migrate({}) r.symlinks({}) end end let(:deploy_to_latest_rev) do basic_deploy_resource.dup.tap do |r| r.revision(latest_rev) r.restart_command shell_restart_command(:deploy_to_latest_rev) end end let(:deploy_to_previous_rev) do basic_deploy_resource.dup.tap do |r| r.revision(previous_rev) r.restart_command shell_restart_command(:deploy_to_previous_rev) end end let(:deploy_to_latest_rev_again) do basic_deploy_resource.dup.tap do |r| r.revision(latest_rev) r.restart_command shell_restart_command(:deploy_to_latest_rev_again) end end # Computes the full path for +path+ relative to the deploy directory def rel_path(path) File.expand_path(path, deploy_directory) end def actual_current_rev Dir.chdir(rel_path("current")) do `git rev-parse HEAD`.strip end end def self.the_app_is_deployed_at_revision(target_rev_spec) it "deploys the app to the target revision (#{target_rev_spec})" do target_rev = send(target_rev_spec) File.should exist(rel_path("current")) actual_current_rev.should == target_rev # Is the app code actually there? File.should exist(rel_path("current/app/app.rb")) end end context "when deploying a simple app" do describe "for the first time, with the required directory layout precreated" do before do FileUtils.mkdir_p(rel_path("releases")) FileUtils.mkdir_p(rel_path("shared")) deploy_to_latest_rev.run_action(:deploy) end the_app_is_deployed_at_revision(:latest_rev) it "restarts the application" do File.should exist(rel_path("current/restart.txt")) actual_operations_order.should == %w[deploy_to_latest_rev] end it "is marked as updated" do deploy_to_latest_rev.should be_updated_by_last_action end end describe "back to a previously deployed revision, with the directory structure precreated" do before do FileUtils.mkdir_p(rel_path("releases")) FileUtils.mkdir_p(rel_path("shared")) deploy_to_latest_rev.run_action(:deploy) deploy_to_previous_rev.run_action(:deploy) deploy_to_latest_rev_again.run_action(:deploy) end the_app_is_deployed_at_revision(:latest_rev) it "restarts the application after rolling back" do actual_operations_order.should == %w[deploy_to_latest_rev deploy_to_previous_rev deploy_to_latest_rev_again] end it "is marked updated" do deploy_to_latest_rev_again.should be_updated_by_last_action end it "deploys the right code" do IO.read(rel_path("current/app/app.rb")).should include("this is the fourth version of the app") end end describe "for the first time, with no existing directory layout" do before do deploy_to_latest_rev.run_action(:deploy) end it "creates the required directory tree" do File.should be_directory(rel_path("releases")) File.should be_directory(rel_path("shared")) File.should be_directory(rel_path("releases/#{latest_rev}")) File.should be_directory(rel_path("current/tmp")) File.should be_directory(rel_path("current/config")) File.should be_directory(rel_path("current/public")) File.should be_symlink(rel_path("current")) File.readlink(rel_path("current")).should == rel_path("releases/#{latest_rev}") end the_app_is_deployed_at_revision(:latest_rev) it "restarts the application" do File.should exist(rel_path("current/restart.txt")) actual_operations_order.should == %w[deploy_to_latest_rev] end it "is marked as updated" do deploy_to_latest_rev.should be_updated_by_last_action end end describe "again to the current revision" do before do deploy_to_latest_rev.run_action(:deploy) deploy_to_latest_rev.run_action(:deploy) end the_app_is_deployed_at_revision(:latest_rev) it "does not restart the app" do actual_operations_order.should == %w[deploy_to_latest_rev] end it "is not marked updated" do deploy_to_latest_rev.should_not be_updated_by_last_action end end describe "again with force_deploy" do before do deploy_to_latest_rev.run_action(:force_deploy) deploy_to_latest_rev_again.run_action(:force_deploy) end the_app_is_deployed_at_revision(:latest_rev) it "restarts the app" do actual_operations_order.should == %w[deploy_to_latest_rev deploy_to_latest_rev_again] end it "is marked updated" do deploy_to_latest_rev.should be_updated_by_last_action end end describe "again to a new revision" do before do deploy_to_previous_rev.run_action(:deploy) deploy_to_latest_rev.run_action(:deploy) end the_app_is_deployed_at_revision(:latest_rev) it "restarts the application after the new deploy" do actual_operations_order.should == %w[deploy_to_previous_rev deploy_to_latest_rev] end it "is marked updated" do deploy_to_previous_rev.should be_updated_by_last_action end it "leaves the old copy of the app around for rollback" do File.should exist(File.join(deploy_directory, "releases", previous_rev)) end end describe "back to a previously deployed revision (implicit rollback)" do before do deploy_to_latest_rev.run_action(:deploy) deploy_to_previous_rev.run_action(:deploy) deploy_to_latest_rev_again.run_action(:deploy) end the_app_is_deployed_at_revision(:latest_rev) it "restarts the application after rolling back" do actual_operations_order.should == %w[deploy_to_latest_rev deploy_to_previous_rev deploy_to_latest_rev_again] end it "is marked updated" do deploy_to_latest_rev_again.should be_updated_by_last_action end it "deploys the right code" do IO.read(rel_path("current/app/app.rb")).should include("this is the fourth version of the app") end end # CHEF-3435 describe "to a deploy_to path that does not yet exist" do let(:top_level_tmpdir) { Dir.mktmpdir } # override top level deploy_directory let block with one that is two # directories deeper let(:deploy_directory) { File.expand_path("nested/deeper", top_level_tmpdir) } after do FileUtils.remove_entry_secure top_level_tmpdir end before do File.should_not exist(deploy_directory) deploy_to_latest_rev.run_action(:deploy) end it "creates the required directory tree" do File.should be_directory(rel_path("releases")) File.should be_directory(rel_path("shared")) File.should be_directory(rel_path("releases/#{latest_rev}")) File.should be_directory(rel_path("current/tmp")) File.should be_directory(rel_path("current/config")) File.should be_directory(rel_path("current/public")) File.should be_symlink(rel_path("current")) File.readlink(rel_path("current")).should == rel_path("releases/#{latest_rev}") end the_app_is_deployed_at_revision(:latest_rev) end end context "when deploying an app with inline recipe callbacks" do # Use closures to capture and mutate this variable. This allows us to track # ordering of operations. callback_order = [] let(:deploy_to_latest_with_inline_recipes) do deploy_to_latest_rev.dup.tap do |r| r.symlink_before_migrate "config/config.ru" => "config.ru" r.before_migrate do callback_order << :before_migrate file "#{release_path}/before_migrate.txt" do # The content here isn't relevant, but it gets printed when running # the tests. Could be handy for debugging. content callback_order.inspect end end r.before_symlink do callback_order << :before_symlink current_release_path = release_path ruby_block "ensure before symlink" do block do if ::File.exist?(::File.join(current_release_path, "/tmp")) raise "Ordering issue with provider, expected symlinks to not have been created" end end end file "#{release_path}/before_symlink.txt" do content callback_order.inspect end end r.before_restart do callback_order << :before_restart current_release_path = release_path ruby_block "ensure after symlink" do block do unless ::File.exist?(::File.join(current_release_path, "/tmp")) raise "Ordering issue with provider, expected symlinks to have been created" end end end file "#{release_path}/tmp/before_restart.txt" do content callback_order.inspect end end r.after_restart do callback_order << :after_restart file "#{release_path}/tmp/after_restart.txt" do content callback_order.inspect end end end end before do callback_order.clear # callback_order variable is global for this context group deploy_to_latest_with_inline_recipes.run_action(:deploy) end the_app_is_deployed_at_revision(:latest_rev) it "is marked updated" do deploy_to_latest_with_inline_recipes.should be_updated_by_last_action end it "calls the callbacks in order" do callback_order.should == [:before_migrate, :before_symlink, :before_restart, :after_restart] end it "runs chef resources in the callbacks" do File.should exist(rel_path("current/before_migrate.txt")) File.should exist(rel_path("current/before_symlink.txt")) File.should exist(rel_path("current/tmp/before_restart.txt")) File.should exist(rel_path("current/tmp/after_restart.txt")) end end context "when deploying an app with in-repo callback scripts" do let(:deploy_with_in_repo_callbacks) do basic_deploy_resource.dup.tap do |r| r.repo git_bundle_with_in_repo_callbacks r.revision rev_with_in_repo_callbacks end end before do deploy_with_in_repo_callbacks.run_action(:deploy) end the_app_is_deployed_at_revision(:rev_with_in_repo_callbacks) it "runs chef resources in the callbacks" do File.should exist(rel_path("current/before_migrate.txt")) File.should exist(rel_path("current/before_symlink.txt")) File.should exist(rel_path("current/tmp/before_restart.txt")) File.should exist(rel_path("current/tmp/after_restart.txt")) end end context "when deploying an app with migrations" do let(:deploy_with_migration) do basic_deploy_resource.dup.tap do |r| # Need this so we can call methods from this test inside the inline # recipe callbacks spec_context = self r.revision latest_rev # enable migrations r.migrate true # abuse `shell_restart_command` so we can observe order of when the # miration command gets run r.migration_command shell_restart_command("migration") r.before_migrate do # inline recipe callbacks don't cwd, so you have to get the release # directory as a local and "capture" it in the closure. current_release = release_path execute spec_context.shell_restart_command("before_migrate") do cwd current_release end end r.before_symlink do current_release = release_path execute spec_context.shell_restart_command("before_symlink") do cwd current_release end end r.before_restart do current_release = release_path execute spec_context.shell_restart_command("before_restart") do cwd current_release end end r.after_restart do current_release = release_path execute spec_context.shell_restart_command("after_restart") do cwd current_release end end end end before do deploy_with_migration.run_action(:deploy) end it "runs migrations in between the before_migrate and before_symlink steps" do actual_operations_order.should == %w[before_migrate migration before_symlink before_restart after_restart] end end context "when deploying an app with in-repo symlinks" do let(:deploy_with_in_repo_symlinks) do basic_deploy_resource.dup.tap do |r| r.repo git_bundle_with_in_repo_symlinks r.revision rev_with_in_repo_symlinks end end it "should not raise an exception calling File.utime on symlinks" do lambda { deploy_with_in_repo_symlinks.run_action(:deploy) }.should_not raise_error end end context "when a previously deployed application has been nuked" do shared_examples_for "a redeployed application" do it "should redeploy the application" do File.should be_directory(rel_path("releases")) File.should be_directory(rel_path("shared")) File.should be_directory(rel_path("releases/#{latest_rev}")) File.should be_directory(rel_path("current/tmp")) File.should be_directory(rel_path("current/config")) File.should be_directory(rel_path("current/public")) File.should be_symlink(rel_path("current")) File.readlink(rel_path("current")).should == rel_path("releases/#{latest_rev}") end end # background: If a deployment is hosed and the user decides to rm -rf the # deployment dir, deploy resource should detect that and nullify its cache. context "by removing the entire deploy directory" do before do deploy_to_latest_rev.dup.run_action(:deploy) FileUtils.rm_rf(deploy_directory) deploy_to_latest_rev.dup.run_action(:deploy) end include_examples "a redeployed application" end context "by removing the current/ directory" do before do deploy_to_latest_rev.dup.run_action(:deploy) FileUtils.rm(rel_path("current")) deploy_to_latest_rev.dup.run_action(:deploy) end include_examples "a redeployed application" end end context "when a deployment fails" do shared_examples_for "a recovered deployment" do it "should redeploy the application" do File.should be_directory(rel_path("releases")) File.should be_directory(rel_path("shared")) File.should be_directory(rel_path("releases/#{latest_rev}")) File.should be_directory(rel_path("current/tmp")) File.should be_directory(rel_path("current/config")) File.should be_directory(rel_path("current/public")) File.should be_symlink(rel_path("current")) File.readlink(rel_path("current")).should == rel_path("releases/#{latest_rev}") # if callbacks ran, we know the app was deployed and not merely rolled # back to a (busted) prior deployment. callback_order.should == [:before_migrate, :before_symlink, :before_restart, :after_restart ] end end let!(:callback_order) { [] } let(:deploy_to_latest_with_callback_tracking) do resource = deploy_to_latest_rev.dup tracker = callback_order resource.before_migrate { tracker << :before_migrate } resource.before_symlink { tracker << :before_symlink } resource.before_restart { tracker << :before_restart } resource.after_restart { tracker << :after_restart } resource end [:before_migrate, :before_symlink, :before_restart, :after_restart].each do |callback| context "in the `#{callback}' callback" do before do lambda { deploy_that_fails.run_action(:deploy) }.should raise_error(Exception, %r{I am a failed deploy}) deploy_to_latest_with_callback_tracking.run_action(:deploy) end let(:deploy_that_fails) do resource = deploy_to_latest_rev.dup errant_callback = lambda {|x| raise Exception, "I am a failed deploy" } resource.send(callback, &errant_callback) resource end include_examples "a recovered deployment" end end context "in the service restart step" do let(:deploy_that_fails) do resource = deploy_to_latest_rev.dup resource.restart_command("RUBYOPT=\"\" ruby -e 'exit 1'") resource end before do lambda { deploy_that_fails.run_action(:deploy) }.should raise_error(Chef::Exceptions::Exec) deploy_to_latest_with_callback_tracking.run_action(:deploy) end include_examples "a recovered deployment" end context "when cloning the app code" do class BadTimeScmProvider def initialize(new_resource, run_context) end def load_current_resource end def revision_slug "5" end def run_action(action) raise RuntimeError, "network error" end end let(:deploy_that_fails) do resource = deploy_to_latest_rev.dup resource.scm_provider(BadTimeScmProvider) resource end before do lambda { deploy_that_fails.run_action(:deploy) }.should raise_error(RuntimeError, /network error/) deploy_to_latest_with_callback_tracking.run_action(:deploy) end include_examples "a recovered deployment" end context "and then is deployed to a different revision" do let(:deploy_that_fails) do resource = deploy_to_previous_rev.dup resource.after_restart {|x| raise Exception, "I am a failed deploy" } resource end before do lambda { deploy_that_fails.run_action(:deploy) }.should raise_error(Exception, %r{I am a failed deploy}) deploy_to_latest_rev.run_action(:deploy) end it "removes the unsuccessful deploy after a later successful deploy" do ::File.should_not exist(File.join(deploy_directory, "releases", previous_rev)) end end end end chef-11.8.2/spec/functional/resource/group_spec.rb0000644000004100000410000001627112254362222022165 0ustar www-datawww-data# # Author:: Chirag Jog () # Author:: Siddheshwar More () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'functional/resource/base' describe Chef::Resource::Group, :requires_root_or_running_windows do def group_should_exist(resource) case ohai[:platform_family] when "debian", "fedora", "rhel", "suse", "gentoo", "slackware", "arch" expect { Etc::getgrnam(resource.name) }.to_not raise_error(ArgumentError, "can't find group for #{resource.name}") expect(resource.name).to eq(Etc::getgrnam(resource.name).name) when "windows" expect { Chef::Util::Windows::NetGroup.new(resource.group_name).local_get_members }.to_not raise_error(ArgumentError, "The group name could not be found.") end end def user_exist_in_group?(resource, user) case ohai[:platform_family] when "debian", "fedora", "rhel", "suse", "gentoo", "slackware", "arch" Etc::getgrnam(resource.name).mem.include?(user) when "windows" Chef::Util::Windows::NetGroup.new(resource.group_name).local_get_members.include?(user) end end def group_should_not_exist(resource) case ohai[:platform_family] when "debian", "fedora", "rhel", "suse", "gentoo", "slackware", "arch" expect { Etc::getgrnam(resource.name) }.to raise_error(ArgumentError, "can't find group for #{resource.name}") when "windows" expect { Chef::Util::Windows::NetGroup.new(resource.group_name).local_get_members }.to raise_error(ArgumentError, "The group name could not be found.") end end def compare_gid(resource, gid) return resource.gid == Etc::getgrnam(resource.name).gid if unix? end def get_user_resource(username) usr = Chef::Resource::User.new("#{username}", run_context) usr.password("Jetsream123!") usr end def create_user(username) get_user_resource(username).run_action(:create) end def remove_user(username) get_user_resource(username).run_action(:remove) end before do @grp_resource = Chef::Resource::Group.new("test-group-#{SecureRandom.random_number(9999)}", run_context) end context "group create action" do after(:each) do @grp_resource.run_action(:remove) end it "create a group" do @grp_resource.run_action(:create) group_should_exist(@grp_resource) end context "group name with 256 characters", :windows_only do before(:each) do grp_name = "theoldmanwalkingdownthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestree" @new_grp = Chef::Resource::Group.new(grp_name, run_context) end after do @new_grp.run_action(:remove) end it " create a group" do @new_grp.run_action(:create) group_should_exist(@new_grp) end end context "group name with more than 256 characters", :windows_only do before(:each) do grp_name = "theoldmanwalkingdownthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQQQQQQQQQQQQ" @new_grp = Chef::Resource::Group.new(grp_name, run_context) end it " not create a group" do expect { @new_grp.run_action(:create) }.to raise_error group_should_not_exist(@new_grp) end end end context "group remove action" do before(:each) do @grp_resource.run_action(:create) end it "remove a group" do @grp_resource.run_action(:remove) group_should_not_exist(@grp_resource) end end context "group modify action", :unsupported_group_provider_platform do before(:each) do @grp_resource.run_action(:create) end after(:each) do @grp_resource.run_action(:remove) end it "add user to group" do user1 = "user1-#{SecureRandom.random_number(9999)}" user2 = "user2-#{SecureRandom.random_number(9999)}" create_user(user1) @grp_resource.members(user1) expect(user_exist_in_group?(@grp_resource, user1)).to be_false @grp_resource.run_action(:modify) group_should_exist(@grp_resource) expect(user_exist_in_group?(@grp_resource, user1)).to be_true create_user(user2) expect(user_exist_in_group?(@grp_resource, user2)).to be_false @grp_resource.members(user2) @grp_resource.run_action(:modify) group_should_exist(@grp_resource) #default append is false, so modify action remove old member user1 from group and add new member user2 expect(user_exist_in_group?(@grp_resource, user1)).to be_false expect(user_exist_in_group?(@grp_resource, user2)).to be_true remove_user(user1) remove_user(user2) end it "append user to a group" do user1 = "user1-#{SecureRandom.random_number(9999)}" user2 = "user2-#{SecureRandom.random_number(9999)}" create_user(user1) @grp_resource.members(user1) expect(user_exist_in_group?(@grp_resource, user1)).to be_false #default append attribute is false @grp_resource.run_action(:modify) group_should_exist(@grp_resource) expect(user_exist_in_group?(@grp_resource, user1)).to be_true #set append attribute to true @grp_resource.append(true) create_user(user2) expect(user_exist_in_group?(@grp_resource, user2)).to be_false @grp_resource.members(user2) @grp_resource.run_action(:modify) group_should_exist(@grp_resource) expect(user_exist_in_group?(@grp_resource, user1)).to be_true expect(user_exist_in_group?(@grp_resource, user2)).to be_true remove_user(user1) remove_user(user2) end it "raise error on add non-existent user to group" do user1 = "user1-#{SecureRandom.random_number(9999)}" @grp_resource.members(user1) @grp_resource.append(true) expect(user_exist_in_group?(@grp_resource, user1)).to be_false expect { @grp_resource.run_action(:modify) }.to raise_error end end context "group manage action", :unix_only, :unsupported_group_provider_platform do before(:each) do @grp_resource.run_action(:create) end after(:each) do @grp_resource.run_action(:remove) end it "change gid of the group" do grp_id = 1234567890 @grp_resource.gid(grp_id) @grp_resource.run_action(:manage) group_should_exist(@grp_resource) expect(compare_gid(@grp_resource, grp_id)).to be_true end end end chef-11.8.2/spec/functional/resource/cron_spec.rb0000644000004100000410000001215512254362222021767 0ustar www-datawww-data# encoding: UTF-8 # # Author:: Kaustubh Deorukhkar () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'functional/resource/base' require 'chef/mixin/shell_out' describe Chef::Resource::Cron, :requires_root, :unix_only do include Chef::Mixin::ShellOut # Platform specific validation routines. def cron_should_exists(cron_name, command) case ohai[:platform] when "aix", "solaris", "opensolaris", "solaris2", "omnios" expect(shell_out("crontab -l #{new_resource.user} | grep \"#{cron_name}\"").exitstatus).to eq(0) expect(shell_out("crontab -l #{new_resource.user} | grep \"#{command}\"").exitstatus).to eq(0) else expect(shell_out("crontab -l -u #{new_resource.user} | grep \"#{cron_name}\"").exitstatus).to eq(0) expect(shell_out("crontab -l -u #{new_resource.user} | grep \"#{command}\"").exitstatus).to eq(0) end end def cron_should_not_exists(cron_name) case ohai[:platform] when "aix", "solaris", "opensolaris", "solaris2", "omnios" expect(shell_out("crontab -l #{new_resource.user} | grep \"#{cron_name}\"").exitstatus).to eq(1) else expect(shell_out("crontab -l -u #{new_resource.user} | grep \"#{cron_name}\"").exitstatus).to eq(1) end end # Actual tests let(:new_resource) do new_resource = Chef::Resource::Cron.new("Chef functional test cron", run_context) new_resource.user 'root' new_resource.minute "30" new_resource.command "/bin/true" new_resource end let(:provider) do provider = new_resource.provider_for_action(new_resource.action) provider end describe "create action" do after do new_resource.run_action(:delete) end it "should create a crontab entry" do new_resource.run_action(:create) cron_should_exists(new_resource.name, new_resource.command) end end describe "delete action" do before do new_resource.run_action(:create) end it "should delete a crontab entry" do # Note that test cron is created by previous test new_resource.run_action(:delete) cron_should_not_exists(new_resource.name) end end exclude_solaris = ["solaris", "opensolaris", "solaris2", "omnios"].include?(ohai[:platform]) describe "create action with various attributes", :external => exclude_solaris do def create_and_validate_with_attribute(resource, attribute, value) if ohai[:platform] == 'aix' expect {resource.run_action(:create)}.to raise_error(Chef::Exceptions::Cron, /Aix cron entry does not support environment variables. Please set them in script and use script in cron./) else resource.run_action(:create) # Verify if the cron is created successfully cron_attribute_should_exists(resource.name, attribute, value) end end def cron_attribute_should_exists(cron_name, attribute, value) return if ['aix', 'solaris'].include?(ohai[:platform]) # Test if the attribute exists on newly created cron cron_should_exists(cron_name, "") expect(shell_out("crontab -l -u #{new_resource.user} | grep \"#{attribute.upcase}=#{value}\"").exitstatus).to eq(0) end after do new_resource.run_action(:delete) end it "should create a crontab entry for mailto attribute" do new_resource.mailto "cheftest@example.com" create_and_validate_with_attribute(new_resource, "mailto", "cheftest@example.com") end it "should create a crontab entry for path attribute" do new_resource.path "/usr/local/bin" create_and_validate_with_attribute(new_resource, "path", "/usr/local/bin") end it "should create a crontab entry for shell attribute" do new_resource.shell "/bin/bash" create_and_validate_with_attribute(new_resource, "shell", "/bin/bash") end it "should create a crontab entry for home attribute" do new_resource.home "/home/opscode" create_and_validate_with_attribute(new_resource, "home", "/home/opscode") end end describe "negative tests for create action" do def cron_create_should_raise_exception expect { new_resource.run_action(:create) }.to raise_error(Chef::Exceptions::Cron, /Error updating state of #{new_resource.name}, exit: 1/) cron_should_not_exists(new_resource.name) end it "should not create cron with invalid minute" do new_resource.minute "invalid" cron_create_should_raise_exception end it "should not create cron with invalid user" do new_resource.user "1-really-really-invalid-user-name" cron_create_should_raise_exception end end end chef-11.8.2/spec/functional/resource/link_spec.rb0000644000004100000410000005233412254362222021766 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' if windows? require 'chef/win32/file' #probably need this in spec_helper end describe Chef::Resource::Link do let(:file_base) { "file_spec" } let(:expect_updated?) {true} # We create the files in a different directory than tmp to exercise # different file deployment strategies more completely. let(:test_file_dir) do if windows? File.join(ENV['systemdrive'], "test-dir") else File.join(CHEF_SPEC_DATA, "test-dir") end end before do FileUtils::mkdir_p(test_file_dir) end after do FileUtils::rm_rf(test_file_dir) end let(:to) do File.join(test_file_dir, make_tmpname("to_spec")) end let(:target_file) do File.join(test_file_dir, make_tmpname("from_spec")) end after(:each) do begin cleanup_link(to) if File.exists?(to) cleanup_link(target_file) if File.exists?(target_file) cleanup_link(CHEF_SPEC_BACKUP_PATH) if File.exists?(CHEF_SPEC_BACKUP_PATH) rescue puts "Could not remove a file: #{$!}" end end def cleanup_link(path) if windows? && File.directory?(path) # If the link target is a directory rm_rf doesn't work all the # time on windows. system "rmdir '#{path}'" else FileUtils.rm_rf(path) end end def canonicalize(path) windows? ? path.gsub('/', '\\') : path end def symlink(a, b) if windows? Chef::ReservedNames::Win32::File.symlink(a, b) else File.symlink(a, b) end end def symlink?(file) if windows? Chef::ReservedNames::Win32::File.symlink?(file) else File.symlink?(file) end end def readlink(file) if windows? Chef::ReservedNames::Win32::File.readlink(file) else File.readlink(file) end end def link(a, b) if windows? Chef::ReservedNames::Win32::File.link(a, b) else File.link(a, b) end end def create_resource node = Chef::Node.new events = Chef::EventDispatch::Dispatcher.new cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) cookbook_collection = Chef::CookbookCollection.new(Chef::CookbookLoader.new(cookbook_repo)) run_context = Chef::RunContext.new(node, cookbook_collection, events) resource = Chef::Resource::Link.new(target_file, run_context) resource.to(to) resource end let(:resource) do create_resource end describe "when supported on platform", :not_supported_on_win2k3 do shared_examples_for 'delete errors out' do it 'delete errors out' do lambda { resource.run_action(:delete) }.should raise_error(Chef::Exceptions::Link) (File.exist?(target_file) || symlink?(target_file)).should be_true end end shared_context 'delete is noop' do describe 'the :delete action' do before(:each) do @info = [] Chef::Log.stub!(:info) { |msg| @info << msg } resource.run_action(:delete) end it 'leaves the file deleted' do File.exist?(target_file).should be_false symlink?(target_file).should be_false end it 'does not mark the resource updated' do resource.should_not be_updated end it 'does not log that it deleted' do @info.include?("link[#{target_file}] deleted").should be_false end end end shared_context 'delete succeeds' do describe 'the :delete action' do before(:each) do @info = [] Chef::Log.stub!(:info) { |msg| @info << msg } resource.run_action(:delete) end it 'deletes the file' do File.exist?(target_file).should be_false symlink?(target_file).should be_false end it 'marks the resource updated' do resource.should be_updated end it 'logs that it deleted' do @info.include?("link[#{target_file}] deleted").should be_true end end end shared_context 'create symbolic link succeeds' do describe 'the :create action' do before(:each) do @info = [] Chef::Log.stub!(:info) { |msg| @info << msg } resource.run_action(:create) end it 'links to the target file' do symlink?(target_file).should be_true readlink(target_file).should == canonicalize(to) end it 'marks the resource updated' do resource.should be_updated end it 'logs that it created' do @info.include?("link[#{target_file}] created").should be_true end end end shared_context 'create symbolic link is noop' do describe 'the :create action' do before(:each) do @info = [] Chef::Log.stub!(:info) { |msg| @info << msg } resource.run_action(:create) end it 'leaves the file linked' do symlink?(target_file).should be_true readlink(target_file).should == canonicalize(to) end it 'does not mark the resource updated' do resource.should_not be_updated end it 'does not log that it created' do @info.include?("link[#{target_file}] created").should be_false end end end shared_context 'create hard link succeeds' do describe 'the :create action' do before(:each) do @info = [] Chef::Log.stub!(:info) { |msg| @info << msg } resource.run_action(:create) end it 'preserves the hard link' do File.exists?(target_file).should be_true symlink?(target_file).should be_false # Writing to one hardlinked file should cause both # to have the new value. IO.read(to).should == IO.read(target_file) File.open(to, "w") { |file| file.write('wowzers') } IO.read(target_file).should == 'wowzers' end it 'marks the resource updated' do resource.should be_updated end it 'logs that it created' do @info.include?("link[#{target_file}] created").should be_true end end end shared_context 'create hard link is noop' do describe 'the :create action' do before(:each) do @info = [] Chef::Log.stub!(:info) { |msg| @info << msg } resource.run_action(:create) end it 'links to the target file' do File.exists?(target_file).should be_true symlink?(target_file).should be_false # Writing to one hardlinked file should cause both # to have the new value. IO.read(to).should == IO.read(target_file) File.open(to, "w") { |file| file.write('wowzers') } IO.read(target_file).should == 'wowzers' end it 'does not mark the resource updated' do resource.should_not be_updated end it 'does not log that it created' do @info.include?("link[#{target_file}] created").should be_false end end end context "is symbolic" do context 'when the link destination is a file' do before(:each) do File.open(to, "w") do |file| file.write('woohoo') end end context 'and the link does not yet exist' do include_context 'create symbolic link succeeds' include_context 'delete is noop' end context 'and the link already exists and is a symbolic link' do context 'pointing at the target' do before(:each) do symlink(to, target_file) symlink?(target_file).should be_true readlink(target_file).should == canonicalize(to) end include_context 'create symbolic link is noop' include_context 'delete succeeds' it 'the :delete action does not delete the target file' do resource.run_action(:delete) File.exists?(to).should be_true end end context 'pointing somewhere else' do before(:each) do @other_target = File.join(test_file_dir, make_tmpname('other_spec')) File.open(@other_target, 'w') { |file| file.write('eek') } symlink(@other_target, target_file) symlink?(target_file).should be_true readlink(target_file).should == canonicalize(@other_target) end after(:each) do File.delete(@other_target) end include_context 'create symbolic link succeeds' include_context 'delete succeeds' it 'the :delete action does not delete the target file' do resource.run_action(:delete) File.exists?(to).should be_true end end context 'pointing nowhere' do before(:each) do nonexistent = File.join(test_file_dir, make_tmpname('nonexistent_spec')) symlink(nonexistent, target_file) symlink?(target_file).should be_true readlink(target_file).should == canonicalize(nonexistent) end include_context 'create symbolic link succeeds' include_context 'delete succeeds' end end context 'and the link already exists and is a hard link to the file' do before(:each) do link(to, target_file) File.exists?(target_file).should be_true symlink?(target_file).should be_false end include_context 'create symbolic link succeeds' it_behaves_like 'delete errors out' end context 'and the link already exists and is a file' do before(:each) do File.open(target_file, 'w') { |file| file.write('eek') } end include_context 'create symbolic link succeeds' it_behaves_like 'delete errors out' end context 'and the link already exists and is a directory' do before(:each) do Dir.mkdir(target_file) end it 'create errors out' do if windows? lambda { resource.run_action(:create) }.should raise_error(Errno::EACCES) elsif os_x? or solaris? or freebsd? or aix? lambda { resource.run_action(:create) }.should raise_error(Errno::EPERM) else lambda { resource.run_action(:create) }.should raise_error(Errno::EISDIR) end end it_behaves_like 'delete errors out' end context 'and the link already exists and is not writeable to this user', :pending do end it_behaves_like 'a securable resource without existing target' do let(:path) { target_file } def allowed_acl(sid, expected_perms) [ ACE.access_allowed(sid, expected_perms[:specific]) ] end def denied_acl(sid, expected_perms) [ ACE.access_denied(sid, expected_perms[:specific]) ] end def parent_inheritable_acls dummy_file_path = File.join(test_file_dir, "dummy_file") dummy_file = FileUtils.touch(dummy_file_path) dummy_desc = get_security_descriptor(dummy_file_path) FileUtils.rm_rf(dummy_file_path) dummy_desc end end end context 'when the link destination is a directory' do before(:each) do Dir.mkdir(to) end # On Windows, readlink fails to open the link. FILE_FLAG_OPEN_REPARSE_POINT # might help, from http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx context 'and the link does not yet exist' do include_context 'create symbolic link succeeds' include_context 'delete is noop' end end context "when the link destination is a symbolic link" do context 'to a file that exists' do before(:each) do @other_target = File.join(test_file_dir, make_tmpname("other_spec")) File.open(@other_target, "w") { |file| file.write("eek") } symlink(@other_target, to) symlink?(to).should be_true readlink(to).should == canonicalize(@other_target) end after(:each) do File.delete(@other_target) end context 'and the link does not yet exist' do include_context 'create symbolic link succeeds' include_context 'delete is noop' end end context 'to a file that does not exist' do before(:each) do @other_target = File.join(test_file_dir, make_tmpname("other_spec")) symlink(@other_target, to) symlink?(to).should be_true readlink(to).should == canonicalize(@other_target) end context 'and the link does not yet exist' do include_context 'create symbolic link succeeds' include_context 'delete is noop' end end end context "when the link destination is not readable to this user", :pending do end context "when the link destination does not exist" do include_context 'create symbolic link succeeds' include_context 'delete is noop' end { '../' => 'with a relative link destination', '' => 'with a bare filename for the link destination' }.each do |prefix, desc| context desc do let(:to) { "#{prefix}#{File.basename(absolute_to)}" } let(:absolute_to) { File.join(test_file_dir, make_tmpname("to_spec")) } before(:each) do resource.to(to) end context 'when the link does not yet exist' do include_context 'create symbolic link succeeds' include_context 'delete is noop' end context 'when the link already exists and points at the target' do before(:each) do symlink(to, target_file) symlink?(target_file).should be_true readlink(target_file).should == canonicalize(to) end include_context 'create symbolic link is noop' include_context 'delete succeeds' end context 'when the link already exists and points at the target with an absolute path' do before(:each) do symlink(absolute_to, target_file) symlink?(target_file).should be_true readlink(target_file).should == canonicalize(absolute_to) end include_context 'create symbolic link succeeds' include_context 'delete succeeds' end end end end context "is a hard link" do before(:each) do resource.link_type(:hard) end context "when the link destination is a file" do before(:each) do File.open(to, "w") do |file| file.write('woohoo') end end context "and the link does not yet exist" do include_context 'create hard link succeeds' include_context 'delete is noop' end context "and the link already exists and is a symbolic link pointing at the same file" do before(:each) do symlink(to, target_file) symlink?(target_file).should be_true readlink(target_file).should == canonicalize(to) end include_context 'create hard link succeeds' it_behaves_like 'delete errors out' end context 'and the link already exists and is a hard link to the file' do before(:each) do link(to, target_file) File.exists?(target_file).should be_true symlink?(target_file).should be_false end include_context 'create hard link is noop' include_context 'delete succeeds' it 'the :delete action does not delete the target file' do resource.run_action(:delete) File.exists?(to).should be_true end end context "and the link already exists and is a file" do before(:each) do File.open(target_file, 'w') { |file| file.write('tomfoolery') } end include_context 'create hard link succeeds' it_behaves_like 'delete errors out' end context "and the link already exists and is a directory" do before(:each) do Dir.mkdir(target_file) end it 'errors out' do if windows? lambda { resource.run_action(:create) }.should raise_error(Errno::EACCES) elsif os_x? or solaris? or freebsd? or aix? lambda { resource.run_action(:create) }.should raise_error(Errno::EPERM) else lambda { resource.run_action(:create) }.should raise_error(Errno::EISDIR) end end it_behaves_like 'delete errors out' end context "and the link already exists and is not writeable to this user", :pending do end context "and specifies security attributes" do before(:each) do resource.owner(windows? ? 'Guest' : 'nobody') end it 'ignores them' do resource.run_action(:create) if windows? Chef::ReservedNames::Win32::Security.get_named_security_info(target_file).owner.should_not == SID.Guest else File.lstat(target_file).uid.should_not == Etc.getpwnam('nobody').uid end end end end context "when the link destination is a directory" do before(:each) do Dir.mkdir(to) end context 'and the link does not yet exist' do it 'create errors out' do lambda { resource.run_action(:create) }.should raise_error(windows? ? Chef::Exceptions::Win32APIError : Errno::EPERM) end include_context 'delete is noop' end end context "when the link destination is a symbolic link" do context 'to a real file' do before(:each) do @other_target = File.join(test_file_dir, make_tmpname("other_spec")) File.open(@other_target, "w") { |file| file.write("eek") } symlink(@other_target, to) symlink?(to).should be_true readlink(to).should == canonicalize(@other_target) end after(:each) do File.delete(@other_target) end context 'and the link does not yet exist' do it 'links to the target file' do resource.run_action(:create) File.exists?(target_file).should be_true # OS X gets angry about this sort of link. Bug in OS X, IMO. pending('OS X/FreeBSD/AIX symlink? and readlink working on hard links to symlinks', :if => (os_x? or freebsd? or aix?)) do symlink?(target_file).should be_true readlink(target_file).should == canonicalize(@other_target) end end include_context 'delete is noop' end end context 'to a nonexistent file' do before(:each) do @other_target = File.join(test_file_dir, make_tmpname("other_spec")) symlink(@other_target, to) symlink?(to).should be_true readlink(to).should == canonicalize(@other_target) end context 'and the link does not yet exist' do it 'links to the target file' do pending('OS X/FreeBSD/AIX fails to create hardlinks to broken symlinks', :if => (os_x? or freebsd? or aix?)) do resource.run_action(:create) # Windows and Unix have different definitions of exists? here, and that's OK. if windows? File.exists?(target_file).should be_true else File.exists?(target_file).should be_false end symlink?(target_file).should be_true readlink(target_file).should == canonicalize(@other_target) end end include_context 'delete is noop' end end end context "when the link destination is not readable to this user", :pending do end context "when the link destination does not exist" do context 'and the link does not yet exist' do it 'create errors out' do lambda { resource.run_action(:create) }.should raise_error(Errno::ENOENT) end include_context 'delete is noop' end end end end describe "when not supported on platform", :win2k3_only do it "raises error" do lambda {resource}.should raise_error(Chef::Exceptions::Win32APIFunctionNotImplemented) end end end chef-11.8.2/spec/functional/resource/mount_spec.rb0000644000004100000410000001443512254362222022173 0ustar www-datawww-data# # Author:: Kaustubh Deorukhkar () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'functional/resource/base' require 'chef/mixin/shell_out' require 'tmpdir' # run this test only for following platforms. include_flag = !(['ubuntu', 'centos', 'aix'].include?(ohai[:platform])) describe Chef::Resource::Mount, :requires_root, :external => include_flag do include Chef::Mixin::ShellOut # Platform specific setup, cleanup and validation helpers. def setup_device_for_mount # use ramdisk for creating a test device for mount. # This can cleaner if we have chef resource/provider for ramdisk. case ohai[:platform] when "aix" ramdisk = shell_out!("mkramdisk 16M").stdout # identify device, for /dev/rramdisk0 it is /dev/ramdisk0 device = ramdisk.tr("\n","").gsub(/\/rramdisk/, '/ramdisk') fstype = "jfs2" shell_out!("mkfs -V #{fstype} #{device}") when "ubuntu", "centos" device = "/dev/ram1" shell_out("ls -1 /dev/ram*").stdout.each_line do |d| if shell_out("mount | grep #{d}").exitstatus == "1" # this device is not mounted, so use it. device = d break end end fstype = "tmpfs" shell_out!("mkfs -q #{device} 512") else end [device, fstype] end def cleanup_device(device) case ohai[:platform] when "aix" ramdisk = device.gsub(/\/ramdisk/, '/rramdisk') shell_out("rmramdisk #{ramdisk}") else end end def cleanup_mount(mount_point) shell_out("umount #{mount_point}") end # platform specific validations. def mount_should_exists(mount_point, device, fstype = nil, options = nil) validation_cmd = "mount | grep #{mount_point} | grep #{device} " validation_cmd << " | grep #{fstype} " unless fstype.nil? validation_cmd << " | grep #{options.join(',')} " unless options.nil? || options.empty? puts "validation_cmd = #{validation_cmd}" expect(shell_out(validation_cmd).exitstatus).to eq(0) end def mount_should_not_exists(mount_point) shell_out("mount").stdout.should_not include(mount_point) end def unix_mount_config_file case ohai[:platform] when 'aix' mount_config = "/etc/filesystems" else mount_config = "/etc/fstab" end end def mount_should_be_enabled(mount_point, device) case ohai[:platform] when 'aix' expect(shell_out("cat #{unix_mount_config_file} | grep \"#{mount_point}:\" ").exitstatus).to eq(0) else expect(shell_out("cat #{unix_mount_config_file} | grep \"#{mount_point}\" | grep \"#{device}\" ").exitstatus).to eq(0) end end def mount_should_be_disabled(mount_point) shell_out("cat #{unix_mount_config_file}").stdout.should_not include("#{mount_point}:") end let(:new_resource) do new_resource = Chef::Resource::Mount.new(@mount_point, run_context) new_resource.device @device new_resource.name @mount_point new_resource.fstype @fstype new_resource.options "log=NULL" if ohai[:platform] == 'aix' new_resource end let(:provider) do provider = new_resource.provider_for_action(new_resource.action) provider end def current_resource provider.load_current_resource provider.current_resource end # Actual tests begin here. before(:all) do @device, @fstype = setup_device_for_mount @mount_point = Dir.mktmpdir("testmount") # Make sure all the potentially leaked mounts are cleared up shell_out("mount").stdout.each_line do |line| if line.include? "testmount" line.split(" ").each do |section| cleanup_mount(section) if section.include? "testmount" end end end end after(:all) do Dir.rmdir(@mount_point) cleanup_device(@device) end after(:each) do cleanup_mount(new_resource.mount_point) end describe "when the target state is a mounted filesystem" do it "should mount the filesystem if it isn't mounted" do current_resource.enabled.should be_false current_resource.mounted.should be_false new_resource.run_action(:mount) new_resource.should be_updated mount_should_exists(new_resource.mount_point, new_resource.device) end end describe "when the filesystem should be remounted and the resource supports remounting" do it "should remount the filesystem if it is mounted" do new_resource.run_action(:mount) mount_should_exists(new_resource.mount_point, new_resource.device) new_resource.supports[:remount] = true new_resource.options "rw,log=NULL" if ohai[:platform] == 'aix' new_resource.run_action(:remount) mount_should_exists(new_resource.mount_point, new_resource.device, nil, (ohai[:platform] == 'aix') ? new_resource.options : nil) end end describe "when the target state is a unmounted filesystem" do it "should umount the filesystem if it is mounted" do new_resource.run_action(:mount) mount_should_exists(new_resource.mount_point, new_resource.device) new_resource.run_action(:umount) mount_should_not_exists(new_resource.mount_point) end end describe "when enabling the filesystem to be mounted" do after do new_resource.run_action(:disable) end it "should enable the mount if it isn't enable" do new_resource.run_action(:mount) new_resource.run_action(:enable) mount_should_be_enabled(new_resource.mount_point, new_resource.device) end end describe "when the target state is to disable the mount" do it "should disable the mount if it is enabled" do new_resource.run_action(:mount) new_resource.run_action(:enable) new_resource.run_action(:disable) mount_should_be_disabled(new_resource.mount_point) end end end chef-11.8.2/spec/functional/resource/ifconfig_spec.rb0000644000004100000410000001120412254362222022604 0ustar www-datawww-data# # Author:: Kaustubh Deorukhkar () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'functional/resource/base' require 'chef/mixin/shell_out' # run this test only for following platforms. include_flag = !(['ubuntu', 'centos', 'aix'].include?(ohai[:platform])) describe Chef::Resource::Ifconfig, :requires_root, :external => include_flag do include Chef::Mixin::ShellOut let(:new_resource) do new_resource = Chef::Resource::Ifconfig.new('10.10.0.1', run_context) new_resource end let(:provider) do provider = new_resource.provider_for_action(new_resource.action) provider end let(:current_resource) do provider.load_current_resource end def lo_interface_for_test # use loopback interface for tests case ohai[:platform] when "aix" 'lo0' else 'lo' end end # **Caution: any updates to core interfaces can be risky. def en0_interface_for_test case ohai[:platform] when "aix" 'en0' else 'eth0' end end def network_interface_alias(interface) case ohai[:platform] when "aix" interface else interface + ":10" end end # platform specific test setup and validation routines def setup_add_interface(resource) resource.device network_interface_alias(en0_interface_for_test) end def setup_enable_interface(resource) resource.device network_interface_alias(en0_interface_for_test) end def interface_should_exists(interface) expect(shell_out("ifconfig #{@interface} | grep 10.10.0.1").exitstatus).to eq(0) end def interface_should_not_exists(interface) expect(shell_out("ifconfig #{@interface} | grep 10.10.0.1").exitstatus).to eq(1) end def interface_persistence_should_exists(interface) case ohai[:platform] when "aix" expect(shell_out("lsattr -E -l #{@interface} | grep 10.10.0.1").exitstatus).to eq(0) else end end def interface_persistence_should_not_exists(interface) case ohai[:platform] when "aix" expect(shell_out("lsattr -E -l #{@interface} | grep 10.10.0.1").exitstatus).to eq(1) else end end # Actual tests describe "#load_current_resource" do it 'should load given interface' do new_resource.device lo_interface_for_test expect(current_resource.device).to eql(lo_interface_for_test) expect(current_resource.inet_addr).to match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) end end exclude_test = ohai[:platform] != 'ubuntu' describe "#action_add", :external => exclude_test do after do new_resource.run_action(:delete) end it "should add interface (vip)" do setup_add_interface(new_resource) new_resource.run_action(:add) interface_should_exists(network_interface_alias(en0_interface_for_test)) interface_persistence_should_exists(network_interface_alias(en0_interface_for_test)) end end describe "#action_enable", :external => exclude_test do after do new_resource.run_action(:disable) end it "should enable interface (vip)" do setup_enable_interface(new_resource) new_resource.run_action(:enable) interface_should_exists(network_interface_alias(en0_interface_for_test)) end end describe "#action_disable", :external => exclude_test do before do setup_enable_interface(new_resource) new_resource.run_action(:enable) end it "should disable interface (vip)" do new_resource.run_action(:disable) new_resource.should be_updated_by_last_action interface_should_not_exists(network_interface_alias(en0_interface_for_test)) end end describe "#action_delete", :external => exclude_test do before do setup_add_interface(new_resource) new_resource.run_action(:add) end it "should delete interface (vip)" do new_resource.run_action(:delete) new_resource.should be_updated_by_last_action interface_should_not_exists(network_interface_alias(en0_interface_for_test)) interface_persistence_should_not_exists(network_interface_alias(en0_interface_for_test)) end end end chef-11.8.2/spec/functional/resource/package_spec.rb0000644000004100000410000002751312254362222022425 0ustar www-datawww-data# encoding: UTF-8 # # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'webrick' module AptServer def enable_testing_apt_source File.open("/etc/apt/sources.list.d/chef-integration-test.list", "w+") do |f| f.puts "deb http://localhost:9000/ sid main" end # Magic to update apt cache for only our repo shell_out!("apt-get update " + '-o Dir::Etc::sourcelist="sources.list.d/chef-integration-test.list" ' + '-o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0"') end def disable_testing_apt_source FileUtils.rm("/etc/apt/sources.list.d/chef-integration-test.list") rescue Errno::ENOENT puts("Attempted to remove integration test from /etc/apt/sources.list.d but it didn't exist") end def tcp_test_port(hostname, port) tcp_socket = TCPSocket.new(hostname, port) true rescue Errno::ETIMEDOUT false rescue Errno::ECONNREFUSED false ensure tcp_socket && tcp_socket.close end def apt_server @apt_server ||= WEBrick::HTTPServer.new( :Port => 9000, :DocumentRoot => apt_data_dir + "/var/www/apt", # Make WEBrick quiet, comment out for debug. :Logger => Logger.new(StringIO.new), :AccessLog => [ StringIO.new, WEBrick::AccessLog::COMMON_LOG_FORMAT ] ) end def run_apt_server apt_server.start end def start_apt_server @apt_server_thread = Thread.new do run_apt_server end until tcp_test_port("localhost", 9000) do if @apt_server_thread.alive? sleep 1 else @apt_server_thread.join raise "apt server failed to start" end end end def stop_apt_server apt_server.shutdown @apt_server_thread.join end def apt_data_dir File.join(CHEF_SPEC_DATA, "apt") end end metadata = { :unix_only => true, :requires_root => true, :provider => {:package => Chef::Provider::Package::Apt}, :arch => "x86_64" # test packages are 64bit } describe Chef::Resource::Package, metadata do include Chef::Mixin::ShellOut context "with a remote package source" do include AptServer before(:all) do # Disable mixlib-shellout live streams Chef::Log.level = :warn start_apt_server enable_testing_apt_source end after(:all) do stop_apt_server disable_testing_apt_source shell_out!("apt-get clean") end after do shell_out!("dpkg -r chef-integration-test") shell_out("dpkg --clear-avail") shell_out!("apt-get clean") end let(:node) do n = Chef::Node.new n.consume_external_attrs(OHAI_SYSTEM.data.dup, {}) n end let(:events) do Chef::EventDispatch::Dispatcher.new end # TODO: lots of duplication from client.rb; # All of this must be setup for preseed files to get found let(:cookbook_collection) do cookbook_path = File.join(CHEF_SPEC_DATA, "cookbooks") cl = Chef::CookbookLoader.new(cookbook_path) cl.load_cookbooks Chef::Cookbook::FileVendor.on_create do |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_path) end Chef::CookbookCollection.new(cl) end let(:run_context) do Chef::RunContext.new(node, cookbook_collection, events) end def base_resource r = Chef::Resource::Package.new("chef-integration-test", run_context) # The apt repository in the spec data is not gpg signed, so we need to # force apt to accept the package: r.options("--force-yes") r end let(:package_resource) do base_resource end context "when the package is not yet installed" do it "installs the package with action :install" do package_resource.run_action(:install) shell_out!("dpkg -l chef-integration-test") package_resource.should be_updated_by_last_action end it "installs the package for action :upgrade" do package_resource.run_action(:upgrade) shell_out!("dpkg -l chef-integration-test") package_resource.should be_updated_by_last_action end it "does nothing for action :remove" do package_resource.run_action(:remove) shell_out!("dpkg -l chef-integration-test", :returns => [1]) package_resource.should_not be_updated_by_last_action end it "does nothing for action :purge" do package_resource.run_action(:purge) shell_out!("dpkg -l chef-integration-test", :returns => [1]) package_resource.should_not be_updated_by_last_action end context "and a not-available package version is specified" do let(:package_resource) do r = base_resource r.version("2.0") r end it "raises a reasonable error for action :install" do expect do package_resource.run_action(:install) end.to raise_error(Mixlib::ShellOut::ShellCommandFailed) end end describe "when preseeding the install" do let(:file_cache_path) { Dir.mktmpdir } before do Chef::Config[:file_cache_path] = file_cache_path debconf_reset = 'chef-integration-test chef-integration-test/sample-var string "INVALID"' shell_out!("echo #{debconf_reset} |debconf-set-selections") end after do FileUtils.rm_rf(file_cache_path) end context "with a preseed file" do let(:package_resource) do r = base_resource r.cookbook_name = "preseed" r.response_file("preseed-file.seed") r end it "preseeds the package, then installs it" do package_resource.run_action(:install) cmd = shell_out!("debconf-show chef-integration-test") cmd.stdout.should include('chef-integration-test/sample-var: "hello world"') package_resource.should be_updated_by_last_action end context "and the preseed file exists and is up-to-date" do before do # Code here is duplicated from the implementation. Not great, but # it should at least fail if the code gets out of sync. source = File.join(CHEF_SPEC_DATA, "cookbooks/preseed/files/default/preseed-file.seed") file_cache_dir = Chef::FileCache.create_cache_path("preseed/preseed") dest = "#{file_cache_dir}/chef-integration-test-1.1-1.seed" FileUtils.cp(source, dest) end it "does not update the package configuration" do package_resource.run_action(:install) cmd = shell_out!("debconf-show chef-integration-test") cmd.stdout.should include('chef-integration-test/sample-var: INVALID') package_resource.should be_updated_by_last_action end end end context "with a preseed template" do # NOTE: in the fixtures, there is also a cookbook_file named # "preseed-template.seed". This implicitly tests that templates are # preferred over cookbook_files when both are present. let(:package_resource) do r = base_resource r.cookbook_name = "preseed" r.response_file("preseed-template.seed") r end before do node.set[:preseed_value] = "FROM TEMPLATE" end it "preseeds the package, then installs it" do package_resource.run_action(:install) cmd = shell_out!("debconf-show chef-integration-test") cmd.stdout.should include('chef-integration-test/sample-var: "FROM TEMPLATE"') package_resource.should be_updated_by_last_action end end end # installing w/ preseed end # when package not installed context "and the desired version of the package is installed" do before do v_1_1_package = File.expand_path("apt/chef-integration-test_1.1-1_amd64.deb", CHEF_SPEC_DATA) shell_out!("dpkg -i #{v_1_1_package}") end it "does nothing for action :install" do package_resource.run_action(:install) shell_out!("dpkg -l chef-integration-test", :returns => [0]) package_resource.should_not be_updated_by_last_action end it "does nothing for action :upgrade" do package_resource.run_action(:upgrade) shell_out!("dpkg -l chef-integration-test", :returns => [0]) package_resource.should_not be_updated_by_last_action end # Verify that the package is removed by running `dpkg -l PACKAGE` # On Ubuntu 12.10 and newer, the command exits 1. # # On Ubuntu 12.04 and older, the `dpkg -l` command will exit 0 and # display a package status message like this: # # Desired=Unknown/Install/Remove/Purge/Hold # | Status=Not/Inst/Cfg-files/Unpacked/Failed-cfg/Half-inst/trig-aWait/Trig-pend # |/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad) # ||/ Name Version Description # +++-=================================-=========================================-============================================ # un chef-integration-test (no description available) def pkg_should_be_removed # will raise if exit code != 0,1 pkg_check = shell_out!("dpkg -l chef-integration-test", :returns => [0,1]) if pkg_check.exitstatus == 0 pkg_check.stdout.should =~ /un[\s]+chef-integration-test/ end end it "removes the package for action :remove" do package_resource.run_action(:remove) pkg_should_be_removed package_resource.should be_updated_by_last_action end it "removes the package for action :purge" do package_resource.run_action(:purge) pkg_should_be_removed package_resource.should be_updated_by_last_action end end context "and an older version of the package is installed" do before do v_1_0_package = File.expand_path("apt/chef-integration-test_1.0-1_amd64.deb", CHEF_SPEC_DATA) shell_out!("dpkg -i #{v_1_0_package}") end it "does nothing for action :install" do package_resource.run_action(:install) shell_out!("dpkg -l chef-integration-test", :returns => [0]) package_resource.should_not be_updated_by_last_action end it "upgrades the package for action :upgrade" do package_resource.run_action(:upgrade) dpkg_l = shell_out!("dpkg -l chef-integration-test", :returns => [0]) dpkg_l.stdout.should =~ /chef\-integration\-test[\s]+1\.1\-1/ package_resource.should be_updated_by_last_action end context "and the resource specifies the new version" do let(:package_resource) do r = base_resource r.version("1.1-1") r end it "upgrades the package for action :install" do package_resource.run_action(:install) dpkg_l = shell_out!("dpkg -l chef-integration-test", :returns => [0]) dpkg_l.stdout.should =~ /chef\-integration\-test[\s]+1\.1\-1/ package_resource.should be_updated_by_last_action end end end end end chef-11.8.2/spec/functional/resource/cookbook_file_spec.rb0000644000004100000410000000534412254362222023635 0ustar www-datawww-data# # Author:: Tim Hinderliter () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::CookbookFile do include_context Chef::Resource::File let(:file_base) { 'cookbook_file_spec' } let(:source) { 'java.response' } let(:cookbook_name) { 'java' } let(:expected_content) do content = File.open(File.join(CHEF_SPEC_DATA, 'cookbooks', 'java', 'files', 'default', 'java.response'), "rb") do |f| f.read end content.force_encoding(Encoding::BINARY) if content.respond_to?(:force_encoding) content end let(:default_mode) { ((0100666 - File.umask) & 07777).to_s(8) } it_behaves_like "a securable resource with reporting" def create_resource # set up cookbook collection for this run to use, based on our # spec data. cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, 'cookbooks')) Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_repo) } loader = Chef::CookbookLoader.new(cookbook_repo) loader.load_cookbooks cookbook_collection = Chef::CookbookCollection.new(loader) node = Chef::Node.new events = Chef::EventDispatch::Dispatcher.new run_context = Chef::RunContext.new(node, cookbook_collection, events) resource = Chef::Resource::CookbookFile.new(path, run_context) resource.cookbook(cookbook_name) resource.source(source) resource end let(:resource) do create_resource end it_behaves_like "a file resource" # These examples cover CHEF-3467 where unexpected and incorrect # permissions can result on Windows because CookbookFile's # implementation # stages files in temp. context "targets a file outside of the system temp directory" do let(:windows_non_temp_dir) { File.join(ENV['systemdrive'], make_tmpname(file_base, "non-temp")) } let(:path) { File.join(windows_non_temp_dir, make_tmpname(file_base)) } before do FileUtils::mkdir_p(windows_non_temp_dir) if Chef::Platform.windows? end after do FileUtils.rm_r(windows_non_temp_dir) if Chef::Platform.windows? && File.exists?(windows_non_temp_dir) end end end chef-11.8.2/spec/functional/resource/user_spec.rb0000644000004100000410000004104412254362222022003 0ustar www-datawww-data# encoding: UTF-8 # # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/mixin/shell_out' metadata = { :unix_only => true, :requires_root => true, :provider => {:user => Chef::Provider::User::Useradd} } describe Chef::Resource::User, metadata do include Chef::Mixin::ShellOut # Utility code for /etc/passwd interaction, avoid any caching of user records: PwEntry = Struct.new(:name, :passwd, :uid, :gid, :gecos, :home, :shell) class UserNotFound < StandardError; end def pw_entry passwd_file = File.open("/etc/passwd", "rb") {|f| f.read} matcher = /^#{Regexp.escape(username)}.+$/ if passwd_entry = passwd_file.scan(matcher).first PwEntry.new(*passwd_entry.split(':')) else raise UserNotFound, "no entry matching #{matcher.inspect} found in /etc/passwd" end end def etc_shadow File.open("/etc/shadow") {|f| f.read } end def supports_quote_in_username? OHAI_SYSTEM["platform_family"] == "debian" end before do pending "porting implementation for user provider in aix" if OHAI_SYSTEM[:platform] == 'aix' # Silence shell_out live stream Chef::Log.level = :warn end after do begin pw_entry # will raise if the user doesn't exist shell_out!("userdel", "-f", "-r", username, :returns => [0,12]) rescue UserNotFound # nothing to remove end end let(:node) do n = Chef::Node.new n.consume_external_attrs(OHAI_SYSTEM.data.dup, {}) n end let(:events) do Chef::EventDispatch::Dispatcher.new end let(:run_context) do Chef::RunContext.new(node, {}, events) end let(:username) do "chef-functional-test" end let(:uid) { nil } let(:home) { nil } let(:manage_home) { false } let(:password) { nil } let(:system) { false } let(:comment) { nil } let(:user_resource) do r = Chef::Resource::User.new("TEST USER RESOURCE", run_context) r.username(username) r.uid(uid) r.home(home) r.comment(comment) r.manage_home(manage_home) r.password(password) r.system(system) r end let(:skip) { false } describe "action :create" do context "when the user does not exist beforehand" do before do if reason = skip pending(reason) end user_resource.run_action(:create) user_resource.should be_updated_by_last_action end it "ensures the user exists" do pw_entry.name.should == username end # On Debian, the only constraints are that usernames must neither start # with a dash ('-') nor plus ('+') nor tilde ('~') nor contain a colon # (':'), a comma (','), or a whitespace (space: ' ', end of line: '\n', # tabulation: '\t', etc.). Note that using a slash ('/') may break the # default algorithm for the definition of the user's home directory. context "and the username contains a single quote" do let(:skip) do if supports_quote_in_username? false else "Platform #{OHAI_SYSTEM["platform"]} not expected to support username w/ quote" end end let(:username) { "t'bilisi" } it "ensures the user exists" do pw_entry.name.should == username end end context "when uid is set" do # Should verify uid not in use... let(:uid) { 1999 } it "ensures the user has the given uid" do pw_entry.uid.should == "1999" end end context "when comment is set" do let(:comment) { "hello this is dog" } it "ensures the comment is set" do pw_entry.gecos.should == "hello this is dog" end context "in standard gecos format" do let(:comment) { "Bobo T. Clown,some building,555-555-5555,@boboclown" } it "ensures the comment is set" do pw_entry.gecos.should == comment end end context "to a string containing multibyte characters" do let(:comment) { "(╯°□°)╯︵ ┻━┻" } it "ensures the comment is set" do actual = pw_entry.gecos actual.force_encoding(Encoding::UTF_8) if "".respond_to?(:force_encoding) actual.should == comment end end context "to a string containing an apostrophe `'`" do let(:comment) { "don't go" } it "ensures the comment is set" do pw_entry.gecos.should == comment end end end context "when home is set" do let(:home) { "/home/#{username}" } it "ensures the user's home is set to the given path" do pw_entry.home.should == "/home/#{username}" end if OHAI_SYSTEM["platform_family"] == "rhel" # Inconsistent behavior. See: CHEF-2205 it "creates the home dir when not explicitly asked to on RHEL (XXX)" do File.should exist("/home/#{username}") end else it "does not create the home dir without `manage_home'" do File.should_not exist("/home/#{username}") end end context "and manage_home is enabled" do let(:manage_home) { true } it "ensures the user's home directory exists" do File.should exist("/home/#{username}") end end end context "when a password is specified" do # openssl passwd -1 "secretpassword" let(:password) { "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" } it "sets the user's shadow password" do pw_entry.passwd.should == "x" expected_shadow = "chef-functional-test:$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" etc_shadow.should include(expected_shadow) end end context "when a system user is specified" do let(:system) { true } let(:uid_min) do # from `man useradd`, login user means uid will be between # UID_SYS_MIN and UID_SYS_MAX defined in /etc/login.defs. On my # Ubuntu 13.04 system, these are commented out, so we'll look at # UID_MIN to find the lower limit of the non-system-user range, and # use that value in our assertions. login_defs = File.open("/etc/login.defs", "rb") {|f| f.read } uid_min_scan = /^UID_MIN\s+(\d+)/ login_defs.match(uid_min_scan)[1] end it "ensures the user has the properties of a system user" do pw_entry.uid.to_i.should be < uid_min.to_i end end end # when the user does not exist beforehand context "when the user already exists" do let(:expect_updated?) { true } let(:existing_uid) { nil } let(:existing_home) { nil } let(:existing_manage_home) { false } let(:existing_password) { nil } let(:existing_system) { false } let(:existing_comment) { nil } let(:existing_user) do r = Chef::Resource::User.new("TEST USER RESOURCE", run_context) # username is identity attr, must match. r.username(username) r.uid(existing_uid) r.home(existing_home) r.comment(existing_comment) r.manage_home(existing_manage_home) r.password(existing_password) r.system(existing_system) r end before do if reason = skip pending(reason) end existing_user.run_action(:create) existing_user.should be_updated_by_last_action user_resource.run_action(:create) user_resource.updated_by_last_action?.should == expect_updated? end context "and all properties are in the desired state" do let(:uid) { 1999 } let(:home) { "/home/bobo" } let(:manage_home) { true } # openssl passwd -1 "secretpassword" let(:password) { "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" } let(:system) { false } let(:comment) { "hello this is dog" } let(:existing_uid) { uid } let(:existing_home) { home } let(:existing_manage_home) { manage_home } let(:existing_password) { password } let(:existing_system) { false } let(:existing_comment) { comment } let(:expect_updated?) { false } it "does not update the user" do user_resource.should_not be_updated end end context "and the uid is updated" do let(:uid) { 1999 } let(:existing_uid) { 1998 } it "ensures the uid is set to the desired value" do pw_entry.uid.should == "1999" end end context "and the comment is updated" do let(:comment) { "hello this is dog" } let(:existing_comment) { "woof" } it "ensures the comment field is set to the desired value" do pw_entry.gecos.should == "hello this is dog" end end context "and home directory is updated" do let(:existing_home) { "/home/foo" } let(:home) { "/home/bar" } it "ensures the home directory is set to the desired value" do pw_entry.home.should == "/home/bar" end context "and manage_home is enabled" do let(:existing_manage_home) { true } let(:manage_home) { true } it "moves the home directory to the new location" do File.should_not exist("/home/foo") File.should exist("/home/bar") end end context "and manage_home wasn't enabled but is now" do let(:existing_manage_home) { false } let(:manage_home) { true } if OHAI_SYSTEM["platform_family"] == "rhel" # Inconsistent behavior. See: CHEF-2205 it "created the home dir b/c of CHEF-2205 so it still exists" do # This behavior seems contrary to expectation and non-convergent. File.should_not exist("/home/foo") File.should exist("/home/bar") end else it "does not create the home dir in the desired location (XXX)" do # This behavior seems contrary to expectation and non-convergent. File.should_not exist("/home/foo") File.should_not exist("/home/bar") end end end context "and manage_home was enabled but is not now" do let(:existing_manage_home) { true } let(:manage_home) { false } it "leaves the old home directory around (XXX)" do # Would it be better to remove the old home? File.should exist("/home/foo") File.should_not exist("/home/bar") end end end context "and a password is added" do # openssl passwd -1 "secretpassword" let(:password) { "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" } it "ensures the password is set" do pw_entry.passwd.should == "x" expected_shadow = "chef-functional-test:$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" etc_shadow.should include(expected_shadow) end end context "and the password is updated" do # openssl passwd -1 "OLDpassword" let(:existing_password) { "$1$1dVmwm4z$CftsFn8eBDjDRUytYKkXB." } # openssl passwd -1 "secretpassword" let(:password) { "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" } it "ensures the password is set to the desired value" do pw_entry.passwd.should == "x" expected_shadow = "chef-functional-test:$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" etc_shadow.should include(expected_shadow) end end context "and the user is changed from not-system to system" do let(:existing_system) { false } let(:system) { true } let(:expect_updated?) { false } it "does not modify the user at all" do end end context "and the user is changed from system to not-system" do let(:existing_system) { true } let(:system) { false } let(:expect_updated?) { false } it "does not modify the user at all" do end end end # when the user already exists end # action :create shared_context "user exists for lock/unlock" do let(:user_locked_context?) { false } def shadow_entry etc_shadow.lines.select {|l| l.include?(username) }.first end def shadow_password shadow_entry.split(':')[1] end before do # create user and setup locked/unlocked state user_resource.dup.run_action(:create) if user_locked_context? shell_out!("usermod -L #{username}") shadow_password.should include("!") elsif password shadow_password.should_not include("!") end end end describe "action :lock" do context "when the user does not exist" do it "raises a sensible error" do expect { user_resource.run_action(:lock) }.to raise_error(Chef::Exceptions::User) end end context "when the user exists" do include_context "user exists for lock/unlock" before do user_resource.run_action(:lock) end context "and the user is not locked" do # user will be locked if it has no password let(:password) { "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" } it "locks the user's password" do shadow_password.should include("!") end end context "and the user is locked" do # user will be locked if it has no password let(:password) { "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" } let(:user_locked_context?) { true } it "does not update the user" do user_resource.should_not be_updated_by_last_action end end end end # action :lock describe "action :unlock" do context "when the user does not exist" do it "raises a sensible error" do expect { user_resource.run_action(:unlock) }.to raise_error(Chef::Exceptions::User) end end context "when the user exists" do include_context "user exists for lock/unlock" before do begin user_resource.run_action(:unlock) @error = nil rescue Exception => e @error = e end end context "and has no password" do # TODO: platform_family should be setup in spec_helper w/ tags if %w[suse opensuse].include?(OHAI_SYSTEM["platform_family"]) # suse gets this right: it "errors out trying to unlock the user" do @error.should be_a(Mixlib::ShellOut::ShellCommandFailed) @error.message.should include("Cannot unlock the password") end else # borked on all other platforms: it "is marked as updated but doesn't modify the user (XXX)" do # This should be an error instead; note that usermod still exits 0 # (which is probably why this case silently fails): # # DEBUG: ---- Begin output of usermod -U chef-functional-test ---- # DEBUG: STDOUT: # DEBUG: STDERR: usermod: unlocking the user's password would result in a passwordless account. # You should set a password with usermod -p to unlock this user's password. # DEBUG: ---- End output of usermod -U chef-functional-test ---- # DEBUG: Ran usermod -U chef-functional-test returned 0 @error.should be_nil pw_entry.passwd.should == 'x' shadow_password.should == "!" end end end context "and has a password" do let(:password) { "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" } context "and the user is not locked" do it "does not update the user" do user_resource.should_not be_updated_by_last_action end end context "and the user is locked" do let(:user_locked_context?) { true } it "unlocks the user's password" do shadow_entry = etc_shadow.lines.select {|l| l.include?(username) }.first shadow_password = shadow_entry.split(':')[1] shadow_password.should_not include("!") end end end end end # action :unlock end chef-11.8.2/spec/functional/resource/directory_spec.rb0000644000004100000410000000236612254362222023035 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Directory do include_context Chef::Resource::Directory let(:directory_base) { "directory_spec" } let(:default_mode) { ((0100777 - File.umask) & 07777).to_s(8) } def create_resource events = Chef::EventDispatch::Dispatcher.new node = Chef::Node.new run_context = Chef::RunContext.new(node, {}, events) Chef::Resource::Directory.new(path, run_context) end let(:resource) do create_resource end it_behaves_like "a directory resource" it_behaves_like "a securable resource with reporting" end chef-11.8.2/spec/functional/resource/remote_directory_spec.rb0000644000004100000410000001526512254362222024412 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::RemoteDirectory do include_context Chef::Resource::Directory let(:directory_base) { "directory_spec" } let(:default_mode) { ((0100777 - File.umask) & 07777).to_s(8) } def create_resource cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_repo) } node = Chef::Node.new cl = Chef::CookbookLoader.new(cookbook_repo) cl.load_cookbooks cookbook_collection = Chef::CookbookCollection.new(cl) events = Chef::EventDispatch::Dispatcher.new run_context = Chef::RunContext.new(node, cookbook_collection, events) resource = Chef::Resource::RemoteDirectory.new(path, run_context) resource.source "remotedir" resource.cookbook('openldap') resource end def create_extraneous_files FileUtils.mkdir_p(File.join(path, 'remotesubdir')) @existing1 = File.join(path, 'marked_for_death.txt') @existing2 = File.join(path, 'remotesubdir', 'marked_for_death_again.txt') FileUtils.touch(@existing1) FileUtils.touch(@existing2) end let(:resource) do create_resource end let(:resource_second_pass) do create_resource end # See spec/data/cookbooks/openldap/files/default let(:expected_files) do [ File.join(path, 'remote_dir_file1.txt'), File.join(path, 'remote_dir_file2.txt'), File.join(path, 'remotesubdir', 'remote_subdir_file1.txt'), File.join(path, 'remotesubdir', 'remote_subdir_file2.txt'), File.join(path, 'remotesubdir', '.a_dotfile'), File.join(path, '.a_dotdir', '.a_dotfile_in_a_dotdir') ] end it_behaves_like "a directory resource" it_behaves_like "a securable resource with reporting" context "when creating the remote directory with purging disabled" do context "and the directory does not yet exist" do before do resource.run_action(:create) end it "transfers the directory with all contents" do expected_files.each do |file_path| File.should exist(file_path) end end it "is marked as updated by last action" do resource.should be_updated_by_last_action end end context "and there are extraneous files in the directory" do before do create_extraneous_files resource.run_action(:create) end it "does not modify the expected state of the directory" do expected_files.each do |file_path| File.should exist(file_path) end end it "does not remove unmanaged files" do File.should exist(@existing1) File.should exist(@existing2) end end context "and the directory is in the desired state" do before do resource.run_action(:create) resource_second_pass.run_action(:create) end it "does not modify the expected state of the directory" do expected_files.each do |file_path| File.should exist(file_path) end end it "is not marked as updated by last action" do resource_second_pass.should_not be_updated_by_last_action end end describe "with overwrite disabled" do before(:each) do resource.purge(false) resource.overwrite(false) end it "leaves modifications alone" do FileUtils.mkdir_p(File.join(path, 'remotesubdir')) modified_file = File.join(path, 'remote_dir_file1.txt') modified_subdir_file = File.join(path, 'remotesubdir', 'remote_subdir_file1.txt') File.open(modified_file, 'a') {|f| f.puts "santa is real"} File.open(modified_subdir_file, 'a') {|f| f.puts "so is rudolph"} modified_file_checksum = sha256_checksum(modified_file) modified_subdir_file_checksum = sha256_checksum(modified_subdir_file) resource.run_action(:create) sha256_checksum(modified_file).should == modified_file_checksum sha256_checksum(modified_subdir_file).should == modified_subdir_file_checksum end end end context "when creating the directory with purging enabled" do before(:each) do resource.purge(true) end context "and there are no extraneous files in the directory" do before do resource.run_action(:create) end it "creates the directory contents as normal" do expected_files.each do |file_path| File.should exist(file_path) end end end context "and there are extraneous files in the directory" do before do create_extraneous_files resource.run_action(:create) end it "removes unmanaged files" do File.should_not exist(@existing1) File.should_not exist(@existing2) end it "does not modify managed files" do expected_files.each do |file_path| File.should exist(file_path) end end it "is marked as updated by last action" do resource.should be_updated_by_last_action end end context "and there are deeply nested extraneous files in the directory" do before do FileUtils.mkdir_p(File.join(path, 'a', 'multiply', 'nested', 'directory')) @existing1 = File.join(path, 'a', 'foo.txt') @existing2 = File.join(path, 'a', 'multiply', 'bar.txt') @existing3 = File.join(path, 'a', 'multiply', 'nested', 'baz.txt') @existing4 = File.join(path, 'a', 'multiply', 'nested', 'directory', 'qux.txt') FileUtils.touch(@existing1) FileUtils.touch(@existing2) FileUtils.touch(@existing3) FileUtils.touch(@existing4) resource.run_action(:create) end it "removes files in subdirectories before files above" do File.should_not exist(@existing1) File.should_not exist(@existing2) File.should_not exist(@existing3) File.should_not exist(@existing4) end it "is marked as updated by last action" do resource.should be_updated_by_last_action end end end end chef-11.8.2/spec/functional/resource/remote_file_spec.rb0000644000004100000410000001101212254362222023307 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'tiny_server' describe Chef::Resource::RemoteFile do let(:file_cache_path) { Dir.mktmpdir } before(:each) do @old_file_cache = Chef::Config[:file_cache_path] Chef::Config[:file_cache_path] = file_cache_path end after(:each) do Chef::Config[:file_cache_path] = @old_file_cache FileUtils.rm_rf(file_cache_path) end include_context Chef::Resource::File let(:file_base) { "remote_file_spec" } def create_resource node = Chef::Node.new events = Chef::EventDispatch::Dispatcher.new run_context = Chef::RunContext.new(node, {}, events) resource = Chef::Resource::RemoteFile.new(path, run_context) resource.source(source) resource end let(:resource) do create_resource end let(:default_mode) { ((0100666 - File.umask) & 07777).to_s(8) } def start_tiny_server(server_opts={}) @server = TinyServer::Manager.new(server_opts) @server.start @api = TinyServer::API.instance @api.clear @api.get("/nyan_cat.png", 200) { File.open(File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png'), "rb") do |f| f.read end } @api.get("/nyan_cat.png.gz", 200, nil, { 'Content-Type' => 'application/gzip', 'Content-Encoding' => 'gzip' } ) { File.open(File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png.gz'), "rb") do |f| f.read end } end def stop_tiny_server @server.stop @server = @api = nil end context "when fetching files over HTTP" do before(:all) do start_tiny_server end after(:all) do stop_tiny_server end describe "when redownload isn't necessary" do let(:source) { 'http://localhost:9000/seattle_capo.png' } before do @api.get("/seattle_capo.png", 304, "", { 'Etag' => 'abcdef' } ) end it "does not fetch the file" do resource.run_action(:create) end end context "when using normal encoding" do let(:source) { 'http://localhost:9000/nyan_cat.png' } let(:expected_content) do content = File.open(File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png'), "rb") do |f| f.read end content.force_encoding(Encoding::BINARY) if content.respond_to?(:force_encoding) content end it_behaves_like "a file resource" it_behaves_like "a securable resource with reporting" end context "when using gzip encoding" do let(:source) { 'http://localhost:9000/nyan_cat.png.gz' } let(:expected_content) do content = File.open(File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png.gz'), "rb") do |f| f.read end content.force_encoding(Encoding::BINARY) if content.respond_to?(:force_encoding) content end it_behaves_like "a file resource" it_behaves_like "a securable resource with reporting" end end context "when fetching files over HTTPS" do before(:all) do cert_text = File.read(File.expand_path("ssl/chef-rspec.cert", CHEF_SPEC_DATA)) cert = OpenSSL::X509::Certificate.new(cert_text) key_text = File.read(File.expand_path("ssl/chef-rspec.key", CHEF_SPEC_DATA)) key = OpenSSL::PKey::RSA.new(key_text) server_opts = { :SSLEnable => true, :SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE, :SSLCertificate => cert, :SSLPrivateKey => key } start_tiny_server(server_opts) end after(:all) do stop_tiny_server end let(:source) { 'https://localhost:9000/nyan_cat.png' } let(:expected_content) do content = File.open(File.join(CHEF_SPEC_DATA, 'remote_file', 'nyan_cat.png'), "rb") do |f| f.read end content.force_encoding(Encoding::BINARY) if content.respond_to?(:force_encoding) content end it_behaves_like "a file resource" end end chef-11.8.2/spec/functional/resource/rpm_spec.rb0000644000004100000410000000767212254362222021634 0ustar www-datawww-data# # Author:: Prabhu Das () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'functional/resource/base' require 'chef/mixin/shell_out' # run this test only for following platforms. exclude_test = !['aix', 'centos', 'redhat', 'suse'].include?(ohai[:platform]) describe Chef::Resource::RpmPackage, :requires_root, :external => exclude_test do include Chef::Mixin::ShellOut let(:new_resource) do new_resource = Chef::Resource::RpmPackage.new(@pkg_name, run_context) new_resource.source @pkg_path new_resource end def rpm_pkg_should_be_installed(resource) case ohai[:platform] # Due to dependency issues , different rpm pkgs are used in different platforms. # dummy rpm package works in aix, without any dependency issues. when "aix" expect(shell_out("rpm -qa | grep dummy").exitstatus).to eq(0) # mytest rpm package works in centos, redhat and in suse without any dependency issues. when "centos", "redhat", "suse" expect(shell_out("rpm -qa | grep mytest").exitstatus).to eq(0) ::File.exists?("/opt/mytest/mytest.sh") # The mytest rpm package contains the mytest.sh file end end def rpm_pkg_should_not_be_installed(resource) case ohai[:platform] when "aix" expect(shell_out("rpm -qa | grep dummy").exitstatus).to eq(1) when "centos", "redhat", "suse" expect(shell_out("rpm -qa | grep mytest").exitstatus).to eq(1) !::File.exists?("/opt/mytest/mytest.sh") end end before(:all) do case ohai[:platform] # Due to dependency issues , different rpm pkgs are used in different platforms. when "aix" @pkg_name = "dummy" @pkg_version = "1-0" @pkg_path = "/tmp/dummy-1-0.aix6.1.noarch.rpm" FileUtils.cp 'spec/functional/assets/dummy-1-0.aix6.1.noarch.rpm' , @pkg_path when "centos", "redhat", "suse" @pkg_name = "mytest" @pkg_version = "1.0-1" @pkg_path = "/tmp/mytest-1.0-1.noarch.rpm" FileUtils.cp 'spec/functional/assets/mytest-1.0-1.noarch.rpm' , @pkg_path end end after(:all) do FileUtils.rm @pkg_path end context "package install action" do it "should create a package" do new_resource.run_action(:install) rpm_pkg_should_be_installed(new_resource) end after(:each) do shell_out("rpm -qa | grep #{@pkg_name}-#{@pkg_version} | xargs rpm -e") end end context "package remove action" do before(:each) do shell_out("rpm -i #{@pkg_path}") end it "should remove an existing package" do new_resource.run_action(:remove) rpm_pkg_should_not_be_installed(new_resource) end end context "package upgrade action" do before(:each) do shell_out("rpm -i #{@pkg_path}") if ohai[:platform] == 'aix' @pkg_version = "2-0" @pkg_path = "/tmp/dummy-2-0.aix6.1.noarch.rpm" FileUtils.cp 'spec/functional/assets/dummy-2-0.aix6.1.noarch.rpm' , @pkg_path else @pkg_version = "2.0-1" @pkg_path = "/tmp/mytest-2.0-1.noarch.rpm" FileUtils.cp 'spec/functional/assets/mytest-2.0-1.noarch.rpm' , @pkg_path end end it "should upgrade a package" do new_resource.run_action(:install) rpm_pkg_should_be_installed(new_resource) end after(:each) do shell_out("rpm -qa | grep #{@pkg_name}-#{@pkg_version} | xargs rpm -e") FileUtils.rm @pkg_path end end end chef-11.8.2/spec/functional/resource/file_spec.rb0000644000004100000410000000612112254362222021741 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::File do include_context Chef::Resource::File let(:file_base) { "file_spec" } let(:expected_content) { "Don't fear the ruby." } def create_resource events = Chef::EventDispatch::Dispatcher.new node = Chef::Node.new run_context = Chef::RunContext.new(node, {}, events) resource = Chef::Resource::File.new(path, run_context) resource end let(:resource) do r = create_resource r.content(expected_content) r end let(:resource_without_content) do create_resource end let(:unmanaged_content) do "This is file content that is not managed by chef" end let(:current_resource) do provider = resource.provider_for_action(resource.action) provider.load_current_resource provider.current_resource end let(:default_mode) { ((0100666 - File.umask) & 07777).to_s(8) } it_behaves_like "a file resource" it_behaves_like "a securable resource with reporting" describe "when running action :create without content" do before do resource_without_content.run_action(:create) end context "and the target file does not exist" do it "creates the file" do File.should exist(path) end it "is marked updated by last action" do resource_without_content.should be_updated_by_last_action end end end describe "when running action :touch" do context "and the target file does not exist" do before do resource.run_action(:touch) end it "it creates the file" do File.should exist(path) end it "is marked updated by last action" do resource.should be_updated_by_last_action end end context "and the target file exists and has the correct content" do before(:each) do File.open(path, "w") { |f| f.print expected_content } @expected_checksum = sha256_checksum(path) now = Time.now.to_i File.utime(now - 9000, now - 9000, path) @expected_mtime = File.stat(path).mtime resource.run_action(:touch) end it "updates the mtime of the file" do File.stat(path).mtime.should > @expected_mtime end it "does not change the content" do sha256_checksum(path).should == @expected_checksum end it "is marked as updated by last action" do resource.should be_updated_by_last_action end end end end chef-11.8.2/spec/functional/resource/registry_spec.rb0000644000004100000410000005775212254362222022712 0ustar www-datawww-data# # Author:: Prajakta Purohit () # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require "chef/win32/registry" require "chef/resource_reporter" require "spec_helper" describe Chef::Resource::RegistryKey, :unix_only do before(:all) do events = Chef::EventDispatch::Dispatcher.new node = Chef::Node.new ohai = Ohai::System.new ohai.all_plugins node.consume_external_attrs(ohai.data,{}) run_context = Chef::RunContext.new(node, {}, events) @resource = Chef::Resource::RegistryKey.new("HKCU\\Software", run_context) end context "when load_current_resource is run on a non-windows node" do it "throws an exception because you don't have a windows registry (derp)" do @resource.key("HKCU\\Software\\Opscode") @resource.values([{:name=>"Color", :type=>:string, :data=>"Orange"}]) lambda{@resource.run_action(:create)}.should raise_error(Chef::Exceptions::Win32NotWindows) end end end describe Chef::Resource::RegistryKey, :windows_only do # parent and key must be single keys, not paths let(:parent) { 'Opscode' } let(:child) { 'Whatever' } let(:key_parent) { "SOFTWARE\\" + parent } let(:key_child) { "SOFTWARE\\" + parent + "\\" + child } # must be under HKLM\SOFTWARE for WOW64 redirection to work let(:reg_parent) { "HKLM\\" + key_parent } let(:reg_child) { "HKLM\\" + key_child } let(:hive_class) { ::Win32::Registry::HKEY_LOCAL_MACHINE } let(:resource_name) { "This is the name of my Resource" } def clean_registry if windows64? # clean 64-bit space on WOW64 @registry.architecture = :x86_64 @registry.delete_key(reg_parent, true) @registry.architecture = :machine end # clean 32-bit space on WOW64 @registry.architecture = :i386 @registry.delete_key(reg_parent, true) @registry.architecture = :machine end def reset_registry clean_registry hive_class.create(key_parent, Win32::Registry::KEY_WRITE | 0x0100) hive_class.create(key_parent, Win32::Registry::KEY_WRITE | 0x0200) end def create_deletable_keys # create them both 32-bit and 64-bit [ 0x0100, 0x0200 ].each do |flag| hive_class.create(key_parent + '\Opscode', Win32::Registry::KEY_WRITE | flag) hive_class.open(key_parent + '\Opscode', Win32::Registry::KEY_ALL_ACCESS | flag) do |reg| reg["Color", Win32::Registry::REG_SZ] = "Orange" reg.write("Opscode", Win32::Registry::REG_MULTI_SZ, ["Seattle", "Washington"]) reg["AKA", Win32::Registry::REG_SZ] = "OC" end hive_class.create(key_parent + '\ReportKey', Win32::Registry::KEY_WRITE | flag) hive_class.open(key_parent + '\ReportKey', Win32::Registry::KEY_ALL_ACCESS | flag) do |reg| reg["ReportVal4", Win32::Registry::REG_SZ] = "report4" reg["ReportVal5", Win32::Registry::REG_SZ] = "report5" end hive_class.create(key_parent + '\OpscodeWhyRun', Win32::Registry::KEY_WRITE | flag) hive_class.open(key_parent + '\OpscodeWhyRun', Win32::Registry::KEY_ALL_ACCESS | flag) do |reg| reg["BriskWalk", Win32::Registry::REG_SZ] = "is good for health" end end end before(:all) do @events = Chef::EventDispatch::Dispatcher.new @node = Chef::Node.new ohai = Ohai::System.new ohai.all_plugins @node.consume_external_attrs(ohai.data,{}) @run_context = Chef::RunContext.new(@node, {}, @events) @new_resource = Chef::Resource::RegistryKey.new(resource_name, @run_context) @registry = Chef::Win32::Registry.new(@run_context) reset_registry end #Reporting setup before do @node.name("windowsbox") @rest_client = mock("Chef::REST (mock)") @rest_client.stub!(:create_url).and_return("reports/nodes/windowsbox/runs/#{@run_id}"); @rest_client.stub!(:raw_http_request).and_return({"result"=>"ok"}); @rest_client.stub!(:post_rest).and_return({"uri"=>"https://example.com/reports/nodes/windowsbox/runs/#{@run_id}"}); @resource_reporter = Chef::ResourceReporter.new(@rest_client) @events.register(@resource_reporter) @run_id = @resource_reporter.run_id @run_status = Chef::RunStatus.new(@node, @events) @resource_reporter.run_started(@run_status) @new_resource.cookbook_name = "monkey" @cookbook_version = mock("Cookbook::Version", :version => "1.2.3") @new_resource.stub!(:cookbook_version).and_return(@cookbook_version) end after (:all) do clean_registry end context "when action is create" do before (:all) do reset_registry end it "creates registry key, value if the key is missing" do @new_resource.key(reg_child) @new_resource.values([{:name=>"Color", :type=>:string, :data=>"Orange"}]) @new_resource.run_action(:create) @registry.key_exists?(reg_child).should == true @registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Orange"}).should == true end it "does not create the key if it already exists with same value, type and data" do @new_resource.key(reg_child) @new_resource.values([{:name=>"Color", :type=>:string, :data=>"Orange"}]) @new_resource.run_action(:create) @registry.key_exists?(reg_child).should == true @registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Orange"}).should == true end it "creates a value if it does not exist" do @new_resource.key(reg_child) @new_resource.values([{:name=>"Mango", :type=>:string, :data=>"Yellow"}]) @new_resource.run_action(:create) @registry.data_exists?(reg_child, {:name=>"Mango", :type=>:string, :data=>"Yellow"}).should == true end it "modifies the data if the key and value exist and type matches" do @new_resource.key(reg_child) @new_resource.values([{:name=>"Color", :type=>:string, :data=>"Not just Orange - OpscodeOrange!"}]) @new_resource.run_action(:create) @registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Not just Orange - OpscodeOrange!"}).should == true end it "modifys the type if the key and value exist and the type does not match" do @new_resource.key(reg_child) @new_resource.values([{:name=>"Color", :type=>:multi_string, :data=>["Not just Orange - OpscodeOrange!"]}]) @new_resource.run_action(:create) @registry.data_exists?(reg_child, {:name=>"Color", :type=>:multi_string, :data=>["Not just Orange - OpscodeOrange!"]}).should == true end it "creates subkey if parent exists" do @new_resource.key(reg_child + '\OpscodeTest') @new_resource.values([{:name=>"Chef", :type=>:multi_string, :data=>["OpscodeOrange", "Rules"]}]) @new_resource.recursive(false) @new_resource.run_action(:create) @registry.key_exists?(reg_child + '\OpscodeTest').should == true @registry.value_exists?(reg_child + '\OpscodeTest', {:name=>"Chef", :type=>:multi_string, :data=>["OpscodeOrange", "Rules"]}).should == true end it "gives error if action create and parent does not exist and recursive is set to false" do @new_resource.key(reg_child + '\Missing1\Missing2') @new_resource.values([{:name=>"OC", :type=>:string, :data=>"MissingData"}]) @new_resource.recursive(false) lambda{@new_resource.run_action(:create)}.should raise_error(Chef::Exceptions::Win32RegNoRecursive) end it "creates missing keys if action create and parent does not exist and recursive is set to true" do @new_resource.key(reg_child + '\Missing1\Missing2') @new_resource.values([{:name=>"OC", :type=>:string, :data=>"MissingData"}]) @new_resource.recursive(true) @new_resource.run_action(:create) @registry.key_exists?(reg_child + '\Missing1\Missing2').should == true @registry.value_exists?(reg_child + '\Missing1\Missing2', {:name=>"OC", :type=>:string, :data=>"MissingData"}).should == true end it "creates key with multiple value as specified" do @new_resource.key(reg_child) @new_resource.values([{:name=>"one", :type=>:string, :data=>"1"},{:name=>"two", :type=>:string, :data=>"2"},{:name=>"three", :type=>:string, :data=>"3"}]) @new_resource.recursive(true) @new_resource.run_action(:create) @new_resource.values.each do |value| @registry.value_exists?(reg_child, value).should == true end end context "when running on 64-bit server", :windows64_only do before(:all) do reset_registry end after(:all) do @new_resource.architecture(:machine) @registry.architecture = :machine end it "creates a key in a 32-bit registry that is not viewable in 64-bit" do @new_resource.key(reg_child + '\Atraxi' ) @new_resource.values([{:name=>"OC", :type=>:string, :data=>"Data"}]) @new_resource.recursive(true) @new_resource.architecture(:i386) @new_resource.run_action(:create) @registry.architecture = :i386 @registry.data_exists?(reg_child + '\Atraxi', {:name=>"OC", :type=>:string, :data=>"Data"}).should == true @registry.architecture = :x86_64 @registry.key_exists?(reg_child + '\Atraxi').should == false end end it "prepares the reporting data for action :create" do @new_resource.key(reg_child + '\Ood') @new_resource.values([{:name=>"ReportingVal1", :type=>:string, :data=>"report1"},{:name=>"ReportingVal2", :type=>:string, :data=>"report2"}]) @new_resource.recursive(true) @new_resource.run_action(:create) @report = @resource_reporter.prepare_run_data @report["action"].should == "end" @report["resources"][0]["type"].should == "registry_key" @report["resources"][0]["name"].should == resource_name @report["resources"][0]["id"].should == reg_child + '\Ood' @report["resources"][0]["after"][:values].should == [{:name=>"ReportingVal1", :type=>:string, :data=>"report1"}, {:name=>"ReportingVal2", :type=>:string, :data=>"report2"}] @report["resources"][0]["before"][:values].should == [] @report["resources"][0]["result"].should == "create" @report["status"].should == "success" @report["total_res_count"].should == "1" end context "while running in whyrun mode" do before (:each) do Chef::Config[:why_run] = true end it "does not throw an exception if the keys do not exist but recursive is set to false" do @new_resource.key(reg_child + '\Slitheen\Raxicoricofallapatorius') @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}]) @new_resource.recursive(false) lambda{@new_resource.run_action(:create)}.should_not raise_error @registry.key_exists?(reg_child + '\Slitheen').should == false @registry.key_exists?(reg_child + '\Slitheen\Raxicoricofallapatorius').should == false end it "does not create key if the action is create" do @new_resource.key(reg_child + '\Slitheen') @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}]) @new_resource.recursive(false) @new_resource.run_action(:create) @registry.key_exists?(reg_child + '\Slitheen').should == false end end end context "when action is create_if_missing" do before (:all) do reset_registry end it "creates registry key, value if the key is missing" do @new_resource.key(reg_child) @new_resource.values([{:name=>"Color", :type=>:string, :data=>"Orange"}]) @new_resource.run_action(:create_if_missing) @registry.key_exists?(reg_parent).should == true @registry.key_exists?(reg_child).should == true @registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Orange"}).should == true end it "does not create the key if it already exists with same value, type and data" do @new_resource.key(reg_child) @new_resource.values([{:name=>"Color", :type=>:string, :data=>"Orange"}]) @new_resource.run_action(:create_if_missing) @registry.key_exists?(reg_child).should == true @registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Orange"}).should == true end it "creates a value if it does not exist" do @new_resource.key(reg_child) @new_resource.values([{:name=>"Mango", :type=>:string, :data=>"Yellow"}]) @new_resource.run_action(:create_if_missing) @registry.data_exists?(reg_child, {:name=>"Mango", :type=>:string, :data=>"Yellow"}).should == true end it "creates subkey if parent exists" do @new_resource.key(reg_child + '\Pyrovile') @new_resource.values([{:name=>"Chef", :type=>:multi_string, :data=>["OpscodeOrange", "Rules"]}]) @new_resource.recursive(false) @new_resource.run_action(:create_if_missing) @registry.key_exists?(reg_child + '\Pyrovile').should == true @registry.value_exists?(reg_child + '\Pyrovile', {:name=>"Chef", :type=>:multi_string, :data=>["OpscodeOrange", "Rules"]}).should == true end it "gives error if action create and parent does not exist and recursive is set to false" do @new_resource.key(reg_child + '\Sontaran\Sontar') @new_resource.values([{:name=>"OC", :type=>:string, :data=>"MissingData"}]) @new_resource.recursive(false) lambda{@new_resource.run_action(:create_if_missing)}.should raise_error(Chef::Exceptions::Win32RegNoRecursive) end it "creates missing keys if action create and parent does not exist and recursive is set to true" do @new_resource.key(reg_child + '\Sontaran\Sontar') @new_resource.values([{:name=>"OC", :type=>:string, :data=>"MissingData"}]) @new_resource.recursive(true) @new_resource.run_action(:create_if_missing) @registry.key_exists?(reg_child + '\Sontaran\Sontar').should == true @registry.value_exists?(reg_child + '\Sontaran\Sontar', {:name=>"OC", :type=>:string, :data=>"MissingData"}).should == true end it "creates key with multiple value as specified" do @new_resource.key(reg_child + '\Adipose') @new_resource.values([{:name=>"one", :type=>:string, :data=>"1"},{:name=>"two", :type=>:string, :data=>"2"},{:name=>"three", :type=>:string, :data=>"3"}]) @new_resource.recursive(true) @new_resource.run_action(:create_if_missing) @new_resource.values.each do |value| @registry.value_exists?(reg_child + '\Adipose', value).should == true end end it "prepares the reporting data for :create_if_missing" do @new_resource.key(reg_child + '\Judoon') @new_resource.values([{:name=>"ReportingVal3", :type=>:string, :data=>"report3"}]) @new_resource.recursive(true) @new_resource.run_action(:create_if_missing) @report = @resource_reporter.prepare_run_data @report["action"].should == "end" @report["resources"][0]["type"].should == "registry_key" @report["resources"][0]["name"].should == resource_name @report["resources"][0]["id"].should == reg_child + '\Judoon' @report["resources"][0]["after"][:values].should == [{:name=>"ReportingVal3", :type=>:string, :data=>"report3"}] @report["resources"][0]["before"][:values].should == [] @report["resources"][0]["result"].should == "create_if_missing" @report["status"].should == "success" @report["total_res_count"].should == "1" end context "while running in whyrun mode" do before (:each) do Chef::Config[:why_run] = true end it "does not throw an exception if the keys do not exist but recursive is set to false" do @new_resource.key(reg_child + '\Zygons\Zygor') @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}]) @new_resource.recursive(false) lambda{@new_resource.run_action(:create_if_missing)}.should_not raise_error @registry.key_exists?(reg_child + '\Zygons').should == false @registry.key_exists?(reg_child + '\Zygons\Zygor').should == false end it "does nothing if the action is create_if_missing" do @new_resource.key(reg_child + '\Zygons') @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}]) @new_resource.recursive(false) @new_resource.run_action(:create_if_missing) @registry.key_exists?(reg_child + '\Zygons').should == false end end end context "when the action is delete" do before(:all) do reset_registry create_deletable_keys end it "takes no action if the specified key path does not exist in the system" do @registry.key_exists?(reg_parent + '\Osirian').should == false @new_resource.key(reg_parent+ '\Osirian') @new_resource.recursive(false) @new_resource.run_action(:delete) @registry.key_exists?(reg_parent + '\Osirian').should == false end it "takes no action if the key exists but the value does not" do @registry.data_exists?(reg_parent + '\Opscode', {:name=>"Color", :type=>:string, :data=>"Orange"}).should == true @new_resource.key(reg_parent + '\Opscode') @new_resource.values([{:name=>"LooksLike", :type=>:multi_string, :data=>["SeattleGrey", "OCOrange"]}]) @new_resource.recursive(false) @new_resource.run_action(:delete) @registry.data_exists?(reg_parent + '\Opscode', {:name=>"Color", :type=>:string, :data=>"Orange"}).should == true end it "deletes only specified values under a key path" do @new_resource.key(reg_parent + '\Opscode') @new_resource.values([{:name=>"Opscode", :type=>:multi_string, :data=>["Seattle", "Washington"]}, {:name=>"AKA", :type=>:string, :data=>"OC"}]) @new_resource.recursive(false) @new_resource.run_action(:delete) @registry.data_exists?(reg_parent + '\Opscode', {:name=>"Color", :type=>:string, :data=>"Orange"}).should == true @registry.value_exists?(reg_parent + '\Opscode', {:name=>"AKA", :type=>:string, :data=>"OC"}).should == false @registry.value_exists?(reg_parent + '\Opscode', {:name=>"Opscode", :type=>:multi_string, :data=>["Seattle", "Washington"]}).should == false end it "it deletes the values with the same name irrespective of it type and data" do @new_resource.key(reg_parent + '\Opscode') @new_resource.values([{:name=>"Color", :type=>:multi_string, :data=>["Black", "Orange"]}]) @new_resource.recursive(false) @new_resource.run_action(:delete) @registry.value_exists?(reg_parent + '\Opscode', {:name=>"Color", :type=>:string, :data=>"Orange"}).should == false end it "prepares the reporting data for action :delete" do @new_resource.key(reg_parent + '\ReportKey') @new_resource.values([{:name=>"ReportVal4", :type=>:string, :data=>"report4"},{:name=>"ReportVal5", :type=>:string, :data=>"report5"}]) @new_resource.recursive(true) @new_resource.run_action(:delete) @report = @resource_reporter.prepare_run_data @registry.value_exists?(reg_parent + '\ReportKey', [{:name=>"ReportVal4", :type=>:string, :data=>"report4"},{:name=>"ReportVal5", :type=>:string, :data=>"report5"}]).should == false @report["action"].should == "end" @report["resources"].count.should == 1 @report["resources"][0]["type"].should == "registry_key" @report["resources"][0]["name"].should == resource_name @report["resources"][0]["id"].should == reg_parent + '\ReportKey' @report["resources"][0]["before"][:values].should == [{:name=>"ReportVal4", :type=>:string, :data=>"report4"}, {:name=>"ReportVal5", :type=>:string, :data=>"report5"}] #Not testing for after values to match since after -> new_resource values. @report["resources"][0]["result"].should == "delete" @report["status"].should == "success" @report["total_res_count"].should == "1" end context "while running in whyrun mode" do before (:each) do Chef::Config[:why_run] = true end it "does nothing if the action is delete" do @new_resource.key(reg_parent + '\OpscodeWhyRun') @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}]) @new_resource.recursive(false) @new_resource.run_action(:delete) @registry.key_exists?(reg_parent + '\OpscodeWhyRun').should == true end end end context "when the action is delete_key" do before (:all) do reset_registry create_deletable_keys end it "takes no action if the specified key path does not exist in the system" do @registry.key_exists?(reg_parent + '\Osirian').should == false @new_resource.key(reg_parent + '\Osirian') @new_resource.recursive(false) @new_resource.run_action(:delete_key) @registry.key_exists?(reg_parent + '\Osirian').should == false end it "deletes key if it has no subkeys and recursive == false" do @new_resource.key(reg_parent + '\OpscodeTest') @new_resource.recursive(false) @new_resource.run_action(:delete_key) @registry.key_exists?(reg_parent + '\OpscodeTest').should == false end it "raises an exception if the key has subkeys and recursive == false" do @new_resource.key(reg_parent) @new_resource.recursive(false) lambda{@new_resource.run_action(:delete_key)}.should raise_error(Chef::Exceptions::Win32RegNoRecursive) end it "ignores the values under a key" do @new_resource.key(reg_parent + '\OpscodeIgnoredValues') #@new_resource.values([{:name=>"DontExist", :type=>:string, :data=>"These will be ignored anyways"}]) @new_resource.recursive(true) @new_resource.run_action(:delete_key) end it "deletes the key if it has subkeys and recursive == true" do @new_resource.key(reg_parent + '\Opscode') @new_resource.recursive(true) @new_resource.run_action(:delete_key) @registry.key_exists?(reg_parent + '\Opscode').should == false end it "prepares the reporting data for action :delete_key" do @new_resource.key(reg_parent + '\ReportKey') @new_resource.recursive(true) @new_resource.run_action(:delete_key) @report = @resource_reporter.prepare_run_data @report["action"].should == "end" @report["resources"][0]["type"].should == "registry_key" @report["resources"][0]["name"].should == resource_name @report["resources"][0]["id"].should == reg_parent + '\ReportKey' #Not testing for before or after values to match since #after -> new_resource.values and #before -> current_resource.values @report["resources"][0]["result"].should == "delete_key" @report["status"].should == "success" @report["total_res_count"].should == "1" end context "while running in whyrun mode" do before (:each) do Chef::Config[:why_run] = true end it "does not throw an exception if the key has subkeys but recursive is set to false" do @new_resource.key(reg_parent + '\OpscodeWhyRun') @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}]) @new_resource.recursive(false) @new_resource.run_action(:delete_key) @new_resource.should_not raise_error(ArgumentError) end it "does nothing if the action is delete_key" do @new_resource.key(reg_parent + '\OpscodeWhyRun') @new_resource.values([{:name=>"BriskWalk",:type=>:string,:data=>"is good for health"}]) @new_resource.recursive(false) @new_resource.run_action(:delete_key) @registry.key_exists?(reg_parent + '\OpscodeWhyRun').should == true end end end end chef-11.8.2/spec/functional/resource/base.rb0000644000004100000410000000232512254362222020724 0ustar www-datawww-data# # Author:: Kaustubh Deorukhkar () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' def ohai # provider is platform-dependent, we need platform ohai data: @OHAI_SYSTEM ||= begin ohai = Ohai::System.new ohai.require_plugin("os") ohai.require_plugin("platform") ohai.require_plugin("passwd") ohai end end def run_context @run_context ||= begin node = Chef::Node.new node.default[:platform] = ohai[:platform] node.default[:platform_version] = ohai[:platform_version] events = Chef::EventDispatch::Dispatcher.new Chef::RunContext.new(node, {}, events) end end chef-11.8.2/spec/functional/resource/template_spec.rb0000644000004100000410000001353312254362222022642 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::Template do def binread(file) File.open(file,"rb") {|f| f.read } end include_context Chef::Resource::File let(:file_base) { "template_spec" } let(:expected_content) { "slappiness is a warm gun" } let(:node) do node = Chef::Node.new node.normal[:slappiness] = "a warm gun" node end def create_resource cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, cookbook_repo) } cl = Chef::CookbookLoader.new(cookbook_repo) cl.load_cookbooks cookbook_collection = Chef::CookbookCollection.new(cl) events = Chef::EventDispatch::Dispatcher.new run_context = Chef::RunContext.new(node, cookbook_collection, events) resource = Chef::Resource::Template.new(path, run_context) resource.source('openldap_stuff.conf.erb') resource.cookbook('openldap') # NOTE: partials rely on `cookbook_name` getting set by chef internals and # ignore the user-set `cookbook` attribute. resource.cookbook_name = "openldap" resource end let(:resource) do create_resource end let(:default_mode) { ((0100666 - File.umask) & 07777).to_s(8) } it_behaves_like "a file resource" it_behaves_like "a securable resource with reporting" context "when the target file does not exist" do it "creates the template with the rendered content using the variable attribute when the :create action is run" do resource.source('openldap_variable_stuff.conf.erb') resource.variables(:secret => "nutella") resource.run_action(:create) IO.read(path).should == "super secret is nutella" end it "creates the template with the rendered content using a local erb file when the :create action is run" do resource.source(File.expand_path(File.join(CHEF_SPEC_DATA,'cookbooks','openldap','templates','default','openldap_stuff.conf.erb'))) resource.cookbook(nil) resource.local(true) resource.run_action(:create) IO.read(path).should == expected_content end end describe "when the template resource defines helper methods" do include_context "diff disabled" let(:resource) do r = create_resource r.source "helper_test.erb" r end let(:expected_content) { "value from helper method" } shared_examples "a template with helpers" do it "generates expected content by calling helper methods" do resource.run_action(:create) binread(path).strip.should == expected_content end end context "using single helper syntax" do before do resource.helper(:helper_method) { "value from helper method" } end it_behaves_like "a template with helpers" end context "using single helper syntax referencing @node" do before do node.set[:helper_test_attr] = "value from helper method" resource.helper(:helper_method) { "#{@node[:helper_test_attr]}" } end it_behaves_like "a template with helpers" end context "using an inline block to define helpers" do before do resource.helpers do def helper_method "value from helper method" end end end it_behaves_like "a template with helpers" end context "using an inline block referencing @node" do before do node.set[:helper_test_attr] = "value from helper method" resource.helpers do def helper_method @node[:helper_test_attr] end end end it_behaves_like "a template with helpers" end context "using a module from a library" do module ExampleModule def helper_method "value from helper method" end end before do resource.helpers(ExampleModule) end it_behaves_like "a template with helpers" end context "using a module from a library referencing @node" do module ExampleModuleReferencingATNode def helper_method @node[:helper_test_attr] end end before do node.set[:helper_test_attr] = "value from helper method" resource.helpers(ExampleModuleReferencingATNode) end it_behaves_like "a template with helpers" end context "using helpers with partial templates" do before do resource.source("helpers_via_partial_test.erb") resource.helper(:helper_method) { "value from helper method" } end it_behaves_like "a template with helpers" end end describe "when template source contains windows style line endings" do include_context "diff disabled" ["all", "some", "no"].each do |test_case| context "for #{test_case} lines" do let(:resource) do r = create_resource r.source "#{test_case}_windows_line_endings.erb" r end it "output should contain platform's line endings" do resource.run_action(:create) binread(path).each_line do |line| line.should end_with(Chef::Platform.windows? ? "\r\n" : "\n") end end end end end end chef-11.8.2/spec/functional/resource/powershell_spec.rb0000644000004100000410000002042712254362222023213 0ustar www-datawww-data# # Author:: Adam Edwards () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe Chef::Resource::WindowsScript::PowershellScript, :windows_only do include_context Chef::Resource::WindowsScript let(:successful_executable_script_content) { "#{ENV['SystemRoot']}\\system32\\attrib.exe $env:systemroot" } let(:failed_executable_script_content) { "#{ENV['SystemRoot']}\\system32\\attrib.exe /badargument" } let(:processor_architecture_script_content) { "echo $env:PROCESSOR_ARCHITECTURE" } let(:native_architecture_script_content) { "echo $env:PROCESSOR_ARCHITECTUREW6432" } let(:cmdlet_exit_code_not_found_content) { "get-item '.\\thisdoesnotexist'" } let(:cmdlet_exit_code_success_content) { "get-item ." } let(:windows_process_exit_code_success_content) { "#{ENV['SystemRoot']}\\system32\\attrib.exe $env:systemroot" } let(:windows_process_exit_code_not_found_content) { "findstr /notavalidswitch" } # Note that process exit codes on 32-bit Win2k3 cannot # exceed maximum value of signed integer let(:arbitrary_nonzero_process_exit_code) { 4193 } let(:arbitrary_nonzero_process_exit_code_content) { "exit #{arbitrary_nonzero_process_exit_code}" } let(:invalid_powershell_interpreter_flag) { "/thisflagisinvalid" } let(:valid_powershell_interpreter_flag) { "-Sta" } let!(:resource) do r = Chef::Resource::WindowsScript::PowershellScript.new("Powershell resource functional test", @run_context) r.code(successful_executable_script_content) r end describe "when the run action is invoked on Windows" do it "successfully executes a non-cmdlet Windows binary as the last command of the script" do resource.code(successful_executable_script_content + " | out-file -encoding ASCII #{script_output_path}") resource.returns(0) resource.run_action(:run) end it "returns the process exit code" do resource.code(arbitrary_nonzero_process_exit_code_content) resource.returns(arbitrary_nonzero_process_exit_code) resource.run_action(:run) end it "returns 0 if the last command was a cmdlet that succeeded" do resource.code(cmdlet_exit_code_success_content) resource.returns(0) resource.run_action(:run) end it "returns 0 if the last command was a cmdlet that succeeded and was preceded by a non-cmdlet Windows binary that failed" do resource.code([windows_process_exit_code_not_found_content, cmdlet_exit_code_success_content].join(';')) resource.returns(0) resource.run_action(:run) end it "returns 1 if the last command was a cmdlet that failed" do resource.code(cmdlet_exit_code_not_found_content) resource.returns(1) resource.run_action(:run) end it "returns 1 if the last command was a cmdlet that failed and was preceded by a successfully executed non-cmdlet Windows binary" do resource.code([windows_process_exit_code_success_content, cmdlet_exit_code_not_found_content].join(';')) resource.returns(1) resource.run_action(:run) end # This somewhat ambiguous case, two failures of different types, # seems to violate the principle of returning the status of the # last line executed -- in this case, we return the status of the # second to last line. This happens because Powershell gives no # way for us to determine whether the last operation was a cmdlet # or Windows process. Because the latter gives more specified # errors than 0 or 1, we return that instead, which is acceptable # since callers can test for nonzero rather than testing for 1. it "returns 1 if the last command was a cmdlet that failed and was preceded by an unsuccessfully executed non-cmdlet Windows binary" do resource.code([arbitrary_nonzero_process_exit_code_content,cmdlet_exit_code_not_found_content].join(';')) resource.returns(arbitrary_nonzero_process_exit_code) resource.run_action(:run) end it "returns 0 if the last command was a non-cmdlet Windows binary that succeeded and was preceded by a failed cmdlet" do resource.code([cmdlet_exit_code_success_content, arbitrary_nonzero_process_exit_code_content].join(';')) resource.returns(arbitrary_nonzero_process_exit_code) resource.run_action(:run) end it "returns a specific error code if the last command was a non-cmdlet Windows binary that failed and was preceded by cmdlet that succeeded" do resource.code([cmdlet_exit_code_success_content, arbitrary_nonzero_process_exit_code_content].join(';')) resource.returns(arbitrary_nonzero_process_exit_code) resource.run_action(:run) end it "returns a specific error code if the last command was a non-cmdlet Windows binary that failed and was preceded by cmdlet that failed" do resource.code([cmdlet_exit_code_not_found_content, arbitrary_nonzero_process_exit_code_content].join(';')) resource.returns(arbitrary_nonzero_process_exit_code) resource.run_action(:run) end it "executes a script with a 64-bit process on a 64-bit OS, otherwise a 32-bit process" do resource.code(processor_architecture_script_content + " | out-file -encoding ASCII #{script_output_path}") resource.returns(0) resource.run_action(:run) is_64_bit = (ENV['PROCESSOR_ARCHITECTURE'] == 'AMD64') || (ENV['PROCESSOR_ARCHITEW6432'] == 'AMD64') detected_64_bit = source_contains_case_insensitive_content?( get_script_output, 'AMD64' ) is_64_bit.should == detected_64_bit end it "returns 1 if an invalid flag is passed to the interpreter" do resource.code(cmdlet_exit_code_success_content) resource.flags(invalid_powershell_interpreter_flag) resource.returns(1) resource.run_action(:run) end it "returns 0 if a valid flag is passed to the interpreter" do resource.code(cmdlet_exit_code_success_content) resource.flags(valid_powershell_interpreter_flag) resource.returns(0) resource.run_action(:run) end end context "when running on a 32-bit version of Windows", :windows32_only do it "executes a script with a 32-bit process if process architecture :i386 is specified" do resource.code(processor_architecture_script_content + " | out-file -encoding ASCII #{script_output_path}") resource.architecture(:i386) resource.returns(0) resource.run_action(:run) source_contains_case_insensitive_content?( get_script_output, 'x86' ).should == true end it "raises an exception if :x86_64 process architecture is specified" do begin resource.architecture(:x86_64).should raise_error Chef::Exceptions::Win32ArchitectureIncorrect rescue Chef::Exceptions::Win32ArchitectureIncorrect end end end context "when running on a 64-bit version of Windows", :windows64_only do it "executes a script with a 64-bit process if :x86_64 arch is specified" do resource.code(processor_architecture_script_content + " | out-file -encoding ASCII #{script_output_path}") resource.architecture(:x86_64) resource.returns(0) resource.run_action(:run) source_contains_case_insensitive_content?( get_script_output, 'AMD64' ).should == true end it "executes a script with a 32-bit process if :i386 arch is specified" do resource.code(processor_architecture_script_content + " | out-file -encoding ASCII #{script_output_path}") resource.architecture(:i386) resource.returns(0) resource.run_action(:run) source_contains_case_insensitive_content?( get_script_output, 'x86' ).should == true end end def get_script_output script_output = File.read(script_output_path) end def source_contains_case_insensitive_content?( source, content ) source.downcase.include?(content.downcase) end end chef-11.8.2/spec/functional/resource/bff_spec.rb0000644000004100000410000000646712254362222021574 0ustar www-datawww-data# # Author:: Prabhu Das () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'functional/resource/base' require 'chef/mixin/shell_out' # Run the test only for AIX platform. describe Chef::Resource::BffPackage, :external => ohai[:platform] != 'aix' do include Chef::Mixin::ShellOut let(:new_resource) do new_resource = Chef::Resource::BffPackage.new(@pkg_name, run_context) new_resource.source @pkg_path new_resource end def bff_pkg_should_be_installed(resource) expect(shell_out("lslpp -L #{resource.name}").exitstatus).to eq(0) ::File.exists?("/usr/PkgA/bin/acommand") end def bff_pkg_should_be_removed(resource) expect(shell_out("lslpp -L #{resource.name}").exitstatus).to eq(1) !::File.exists?("/usr/PkgA/bin/acommand") end before(:all) do @pkg_name = "PkgA.rte" @pkg_path = "/tmp/PkgA.1.0.0.0.bff" FileUtils.cp 'spec/functional/assets/PkgA.1.0.0.0.bff' , @pkg_path end after(:all) do FileUtils.rm @pkg_path end context "package install action" do it "should install a package" do new_resource.run_action(:install) bff_pkg_should_be_installed(new_resource) end after(:each) do shell_out("installp -u #{@pkg_name}") end end context "package install action with options" do it "should install a package" do new_resource.options("-e/tmp/installp.log") new_resource.run_action(:install) bff_pkg_should_be_installed(new_resource) end after(:each) do shell_out("installp -u #{@pkg_name}") FileUtils.rm "/tmp/installp.log" end end context "package upgrade action" do before(:each) do shell_out("installp -aYF -d #{@pkg_path} #{@pkg_name}") @pkg_path = "/tmp/PkgA.2.0.0.0.bff" FileUtils.cp 'spec/functional/assets/PkgA.2.0.0.0.bff' , @pkg_path end it "should upgrade package" do new_resource.run_action(:install) bff_pkg_should_be_installed(new_resource) end after(:each) do shell_out("installp -u #{@pkg_name}") FileUtils.rm @pkg_path end end context "package remove action" do before(:each) do shell_out("installp -aYF -d #{@pkg_path} #{@pkg_name}") end it "should remove an installed package" do new_resource.run_action(:remove) bff_pkg_should_be_removed(new_resource) end end context "package remove action with options" do before(:each) do shell_out("installp -aYF -d #{@pkg_path} #{@pkg_name}") end it "should remove an installed package" do new_resource.options("-e/tmp/installp.log") new_resource.run_action(:remove) bff_pkg_should_be_removed(new_resource) end after(:each) do FileUtils.rm "/tmp/installp.log" end end end chef-11.8.2/spec/functional/version_spec.rb0000644000004100000410000000232612254362222020663 0ustar www-datawww-data# # Author:: Serdar Sutay () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require File.expand_path('../../spec_helper', __FILE__) require 'chef/mixin/shell_out' require 'chef/version' require 'ohai/version' describe "Chef Versions" do include Chef::Mixin::ShellOut let(:chef_dir) { File.join(File.dirname(__FILE__), "..", "..") } binaries = [ "chef-client", "chef-shell", "chef-apply", "knife", "chef-solo" ] binaries.each do |binary| it "#{binary} version should be sane" do shell_out!("ruby #{File.join("bin", binary)} -v", :cwd => chef_dir).stdout.chomp.should == "Chef: #{Chef::VERSION}" end end end chef-11.8.2/spec/functional/win32/0000755000004100000410000000000012254362222016576 5ustar www-datawww-datachef-11.8.2/spec/functional/win32/versions_spec.rb0000644000004100000410000000550612254362222022013 0ustar www-datawww-data# # Author:: Chirag Jog () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' if Chef::Platform.windows? require 'chef/win32/version' require 'ruby-wmi' end describe "Chef::ReservedNames::Win32::Version", :windows_only do before do host = WMI::Win32_OperatingSystem.find(:first) # Use WMI to determine current OS version. # On Win2k8R2 and later, we can dynamically obtain marketing # names for comparison from WMI so the test should not # need to be modified when new Windows releases arise. # For Win2k3 and Win2k8, we use static names in this test # based on the version number information from WMI. The names # from WMI contain extended characters such as registered # trademark on Win2k8 and Win2k3 that we're not using in our # library, so we have to set the expectation statically. if Chef::Platform::windows_server_2003? @current_os_version = 'Windows Server 2003 R2' elsif is_windows_server_2008?(host) @current_os_version = 'Windows Server 2008' else # The name from WMI is actually what we want in Win2k8R2+. # So this expectation sould continue to hold without modification # as new versions of Windows are released. @current_os_version = host.caption end @version = Chef::ReservedNames::Win32::Version.new end context "Windows Operating System version" do it "should match the version from WMI" do @current_os_version.should include(@version.marketing_name) end end def is_windows_server_2008?(wmi_host) is_win2k8 = false os_version = wmi_host.send('Version') # The operating system version is a string in the following form # that can be split into components based on the '.' delimiter: # MajorVersionNumber.MinorVersionNumber.BuildNumber os_version_components = os_version.split('.') if os_version_components.length < 2 raise 'WMI returned a Windows version from Win32_OperatingSystem.Version ' + 'with an unexpected format. The Windows version could not be determined.' end # Windows 6.0 is Windows Server 2008, so test the major and # minor version components is_win2k8 = os_version_components[0] == '6' && os_version_components[1] == '0' end end chef-11.8.2/spec/functional/win32/security_spec.rb0000644000004100000410000000250312254362222022004 0ustar www-datawww-data# # Author:: Serdar Sutay () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' if Chef::Platform.windows? require 'chef/win32/security' end describe 'Chef::Win32::Security', :windows_only do it "has_admin_privileges? returns true when running as admin" do Chef::ReservedNames::Win32::Security.has_admin_privileges?.should == true end # We've done some investigation adding a negative test and it turned # out to be a lot of work since mixlib-shellout doesn't have user # support for windows. # # TODO - Add negative tests once mixlib-shellout has user support it "has_admin_privileges? returns false when running as non-admin" do pending "requires user support in mixlib-shellout" end end chef-11.8.2/spec/functional/win32/registry_helper_spec.rb0000644000004100000410000007362512254362222023361 0ustar www-datawww-data# # Author:: Prajakta Purohit () # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'chef/win32/registry' describe Chef::Resource::RegistryKey, :unix_only do before(:all) do events = Chef::EventDispatch::Dispatcher.new node = Chef::Node.new ohai = Ohai::System.new ohai.all_plugins node.consume_external_attrs(ohai.data,{}) run_context = Chef::RunContext.new(node, {}, events) @resource = Chef::Resource::RegistryKey.new("HKCU\\Software", run_context) end context "when load_current_resource is run on a non-windows node" do it "throws an exception because you don't have a windows registry (derp)" do @resource.key("HKCU\\Software\\Opscode") @resource.values([{:name=>"Color", :type=>:string, :data=>"Orange"}]) lambda{@resource.run_action(:create)}.should raise_error(Chef::Exceptions::Win32NotWindows) end end end describe 'Chef::Win32::Registry', :windows_only do before(:all) do #Create a registry item ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root" ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Branch" ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Branch\\Flower" ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root', Win32::Registry::KEY_ALL_ACCESS) do |reg| reg['RootType1', Win32::Registry::REG_SZ] = 'fibrous' reg.write('Roots', Win32::Registry::REG_MULTI_SZ, ["strong roots", "healthy tree"]) end ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Branch', Win32::Registry::KEY_ALL_ACCESS) do |reg| reg['Strong', Win32::Registry::REG_SZ] = 'bird nest' end ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Branch\\Flower', Win32::Registry::KEY_ALL_ACCESS) do |reg| reg['Petals', Win32::Registry::REG_MULTI_SZ] = ["Pink", "Delicate"] end #Create the node with ohai data events = Chef::EventDispatch::Dispatcher.new @node = Chef::Node.new ohai = Ohai::System.new ohai.all_plugins @node.consume_external_attrs(ohai.data,{}) @run_context = Chef::RunContext.new(@node, {}, events) #Create a registry object that has access ot the node previously created @registry = Chef::Win32::Registry.new(@run_context) end #Delete what is left of the registry key-values previously created after(:all) do ::Win32::Registry::HKEY_CURRENT_USER.open("Software") do |reg| reg.delete_key("Root", true) end end # Server Versions # it "succeeds if server versiion is 2003R2, 2008, 2008R2, 2012" do # end # it "falis if the server versions are anything else" do # end describe "hive_exists?" do it "returns true if the hive exists" do @registry.hive_exists?("HKCU\\Software\\Root").should == true end it "returns false if the hive does not exist" do hive = @registry.hive_exists?("LYRU\\Software\\Root").should == false end end describe "key_exists?" do it "returns true if the key path exists" do @registry.key_exists?("HKCU\\Software\\Root\\Branch\\Flower").should == true end it "returns false if the key path does not exist" do @registry.key_exists?("HKCU\\Software\\Branch\\Flower").should == false end it "throws an exception if the hive does not exist" do lambda {@registry.key_exists?("JKLM\\Software\\Branch\\Flower")}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) end end describe "key_exists!" do it "returns true if the key path exists" do @registry.key_exists!("HKCU\\Software\\Root\\Branch\\Flower").should == true end it "throws an exception if the key path does not exist" do lambda {@registry.key_exists!("HKCU\\Software\\Branch\\Flower")}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end it "throws an exception if the hive does not exist" do lambda {@registry.key_exists!("JKLM\\Software\\Branch\\Flower")}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) end end describe "value_exists?" do it "throws an exception if the hive does not exist" do lambda {@registry.value_exists?("JKLM\\Software\\Branch\\Flower", {:name=>"Petals"})}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) end it "throws an exception if the key does not exist" do lambda {@registry.value_exists?("HKCU\\Software\\Branch\\Flower", {:name=>"Petals"})}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end it "returns true if the value exists" do @registry.value_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals"}).should == true end it "returns false if the value does not exist" do @registry.value_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"FOOBAR"}).should == false end end describe "value_exists!" do it "throws an exception if the hive does not exist" do lambda {@registry.value_exists!("JKLM\\Software\\Branch\\Flower", {:name=>"Petals"})}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) end it "throws an exception if the key does not exist" do lambda {@registry.value_exists!("HKCU\\Software\\Branch\\Flower", {:name=>"Petals"})}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end it "returns true if the value exists" do @registry.value_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals"}).should == true end it "throws an exception if the value does not exist" do lambda {@registry.value_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"FOOBAR"})}.should raise_error(Chef::Exceptions::Win32RegValueMissing) end end describe "data_exists?" do it "throws an exception if the hive does not exist" do lambda {@registry.data_exists?("JKLM\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) end it "throws an exception if the key does not exist" do lambda {@registry.data_exists?("HKCU\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end it "returns true if all the data matches" do @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]}).should == true end it "returns false if the name does not exist" do @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"slateP", :type=>:multi_string, :data=>["Pink", "Delicate"]}).should == false end it "returns false if the types do not match" do @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:string, :data=>"Pink"}).should == false end it "returns false if the data does not match" do @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Mauve", "Delicate"]}).should == false end end describe "data_exists!" do it "throws an exception if the hive does not exist" do lambda {@registry.data_exists!("JKLM\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) end it "throws an exception if the key does not exist" do lambda {@registry.data_exists!("HKCU\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end it "returns true if all the data matches" do @registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]}).should == true end it "throws an exception if the name does not exist" do lambda {@registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"slateP", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.should raise_error(Chef::Exceptions::Win32RegDataMissing) end it "throws an exception if the types do not match" do lambda {@registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:string, :data=>"Pink"})}.should raise_error(Chef::Exceptions::Win32RegDataMissing) end it "throws an exception if the data does not match" do lambda {@registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Mauve", "Delicate"]})}.should raise_error(Chef::Exceptions::Win32RegDataMissing) end end describe "get_values" do it "returns all values for a key if it exists" do values = @registry.get_values("HKCU\\Software\\Root") values.should be_an_instance_of Array values.should == [{:name=>"RootType1", :type=>:string, :data=>"fibrous"}, {:name=>"Roots", :type=>:multi_string, :data=>["strong roots", "healthy tree"]}] end it "throws an exception if the key does not exist" do lambda {@registry.get_values("HKCU\\Software\\Branch\\Flower")}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end it "throws an exception if the hive does not exist" do lambda {@registry.get_values("JKLM\\Software\\Branch\\Flower")}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) end end describe "set_value" do it "updates a value if the key, value exist and type matches and value different" do @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]}).should == true @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]}).should == true end it "updates a value if the type does match and the values are different" do @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:string, :data=>"Yellow"}).should == true @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:string, :data=>"Yellow"}).should == true @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]}).should == false end it "creates a value if key exists and value does not" do @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Stamen", :type=>:multi_string, :data=>["Yellow", "Changed Color"]}).should == true @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Stamen", :type=>:multi_string, :data=>["Yellow", "Changed Color"]}).should == true end it "does nothing if data,type and name parameters for the value are same" do @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Stamen", :type=>:multi_string, :data=>["Yellow", "Changed Color"]}).should == false @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Stamen", :type=>:multi_string, :data=>["Yellow", "Changed Color"]}).should == true end it "throws an exception if the key does not exist" do lambda {@registry.set_value("HKCU\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end it "throws an exception if the hive does not exist" do lambda {@registry.set_value("JKLM\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) end # we are validating that the data gets .to_i called on it when type is a :dword it "casts an integer string given as a dword into an integer" do @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBe32767", :type=>:dword, :data=>"32767"}).should == true @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBe32767", :type=>:dword, :data=>32767}).should == true end it "casts a nonsense string given as a dword into zero" do @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBeZero", :type=>:dword, :data=>"whatdoesthisdo"}).should == true @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBeZero", :type=>:dword, :data=>0}).should == true end it "throws an exception when trying to cast an array to an int for a dword" do lambda {@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldThrow", :type=>:dword, :data=>["one","two"]})}.should raise_error end # we are validating that the data gets .to_s called on it when type is a :string it "stores the string representation of an array into a string if you pass it an array" do @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBePainful", :type=>:string, :data=>["one","two"]}).should == true @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBePainful", :type=>:string, :data=>'["one", "two"]'}).should == true end it "stores the string representation of a number into a string if you pass it an number" do @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBe65535", :type=>:string, :data=>65535}).should == true @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBe65535", :type=>:string, :data=>"65535"}).should == true end # we are validating that the data gets .to_a called on it when type is a :multi_string it "throws an exception when a multi-string is passed a number" do lambda {@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldThrow", :type=>:multi_string, :data=>65535})}.should raise_error end it "throws an exception when a multi-string is passed a string" do lambda {@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBeWat", :type=>:multi_string, :data=>"foo"})}.should raise_error end end describe "create_key" do before(:all) do ::Win32::Registry::HKEY_CURRENT_USER.open("Software\\Root") do |reg| begin reg.delete_key("Trunk", true) rescue end end end it "throws an exception if the path has missing keys but recursive set to false" do lambda {@registry.create_key("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", false)}.should raise_error(Chef::Exceptions::Win32RegNoRecursive) @registry.key_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker").should == false end it "creates the key_path if the keys were missing but recursive was set to true" do @registry.create_key("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", true).should == true @registry.key_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker").should == true end it "does nothing if the key already exists" do @registry.create_key("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", false).should == true @registry.key_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker").should == true end it "throws an exception of the hive does not exist" do lambda {@registry.create_key("JKLM\\Software\\Root\\Trunk\\Peck\\Woodpecker", false)}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) end end describe "delete_value" do before(:all) do ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Trunk\\Peck\\Woodpecker" ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Trunk\\Peck\\Woodpecker', Win32::Registry::KEY_ALL_ACCESS) do |reg| reg['Peter', Win32::Registry::REG_SZ] = 'Tiny' end end it "deletes values if the value exists" do @registry.delete_value("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"}).should == true @registry.value_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"}).should == false end it "does nothing if value does not exist" do @registry.delete_value("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"}).should == true @registry.value_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"}).should == false end it "throws an exception if the key does not exist?" do lambda {@registry.delete_value("HKCU\\Software\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"})}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end it "throws an exception if the hive does not exist" do lambda {@registry.delete_value("JKLM\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"})}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) end end describe "delete_key" do before (:all) do ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Branch\\Fruit" ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Branch\\Fruit', Win32::Registry::KEY_ALL_ACCESS) do |reg| reg['Apple', Win32::Registry::REG_MULTI_SZ] = ["Red", "Juicy"] end ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Trunk\\Peck\\Woodpecker" ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root\\Trunk\\Peck\\Woodpecker', Win32::Registry::KEY_ALL_ACCESS) do |reg| reg['Peter', Win32::Registry::REG_SZ] = 'Tiny' end end it "deletes a key if it has no subkeys" do @registry.delete_key("HKCU\\Software\\Root\\Branch\\Fruit", false).should == true @registry.key_exists?("HKCU\\Software\\Root\\Branch\\Fruit").should == false end it "throws an exception if key to delete has subkeys and recursive is false" do lambda { @registry.delete_key("HKCU\\Software\\Root\\Trunk", false) }.should raise_error(Chef::Exceptions::Win32RegNoRecursive) @registry.key_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker").should == true end it "deletes a key if it has subkeys and recursive true" do @registry.delete_key("HKCU\\Software\\Root\\Trunk", true).should == true @registry.key_exists?("HKCU\\Software\\Root\\Trunk").should == false end it "does nothing if the key does not exist" do @registry.delete_key("HKCU\\Software\\Root\\Trunk", true).should == true @registry.key_exists?("HKCU\\Software\\Root\\Trunk").should == false end it "throws an exception if the hive does not exist" do lambda {@registry.delete_key("JKLM\\Software\\Root\\Branch\\Flower", false)}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) end end describe "has_subkeys?" do before(:all) do ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Trunk" ::Win32::Registry::HKEY_CURRENT_USER.open("Software\\Root\\Trunk") do |reg| begin reg.delete_key("Red", true) rescue end end end it "throws an exception if the hive was missing" do lambda {@registry.has_subkeys?("LMNO\\Software\\Root")}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) end it "throws an exception if the key is missing" do lambda {@registry.has_subkeys?("HKCU\\Software\\Root\\Trunk\\Red")}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end it "returns true if the key has subkeys" do @registry.has_subkeys?("HKCU\\Software\\Root").should == true end it "returns false if the key has no subkeys" do ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Trunk\\Red" @registry.has_subkeys?("HKCU\\Software\\Root\\Trunk\\Red").should == false end end describe "get_subkeys" do it "throws an exception if the key is missing" do lambda {@registry.get_subkeys("HKCU\\Software\\Trunk\\Red")}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end it "throws an exception if the hive does not exist" do lambda {@registry.get_subkeys("JKLM\\Software\\Root")}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) end it "returns the array of subkeys for a given key" do subkeys = @registry.get_subkeys("HKCU\\Software\\Root") reg_subkeys = [] ::Win32::Registry::HKEY_CURRENT_USER.open("Software\\Root", Win32::Registry::KEY_ALL_ACCESS) do |reg| reg.each_key{|name| reg_subkeys << name} end reg_subkeys.should == subkeys end end describe "architecture" do describe "on 32-bit" do before(:all) do @saved_kernel_machine = @node.automatic_attrs[:kernel][:machine] @node.automatic_attrs[:kernel][:machine] = :i386 end after(:all) do @node.automatic_attrs[:kernel][:machine] = @saved_kernel_machine end context "registry constructor" do it "throws an exception if requested architecture is 64bit but running on 32bit" do lambda {Chef::Win32::Registry.new(@run_context, :x86_64)}.should raise_error(Chef::Exceptions::Win32RegArchitectureIncorrect) end it "can correctly set the requested architecture to 32-bit" do @r = Chef::Win32::Registry.new(@run_context, :i386) @r.architecture.should == :i386 @r.registry_system_architecture.should == 0x0200 end it "can correctly set the requested architecture to :machine" do @r = Chef::Win32::Registry.new(@run_context, :machine) @r.architecture.should == :machine @r.registry_system_architecture.should == 0x0200 end end context "architecture setter" do it "throws an exception if requested architecture is 64bit but running on 32bit" do lambda {@registry.architecture = :x86_64}.should raise_error(Chef::Exceptions::Win32RegArchitectureIncorrect) end it "sets the requested architecture to :machine if passed :machine" do @registry.architecture = :machine @registry.architecture.should == :machine @registry.registry_system_architecture.should == 0x0200 end it "sets the requested architecture to 32-bit if passed i386 as a string" do @registry.architecture = :i386 @registry.architecture.should == :i386 @registry.registry_system_architecture.should == 0x0200 end end end describe "on 64-bit" do before(:all) do @saved_kernel_machine = @node.automatic_attrs[:kernel][:machine] @node.automatic_attrs[:kernel][:machine] = :x86_64 end after(:all) do @node.automatic_attrs[:kernel][:machine] = @saved_kernel_machine end context "registry constructor" do it "can correctly set the requested architecture to 32-bit" do @r = Chef::Win32::Registry.new(@run_context, :i386) @r.architecture.should == :i386 @r.registry_system_architecture.should == 0x0200 end it "can correctly set the requested architecture to 64-bit" do @r = Chef::Win32::Registry.new(@run_context, :x86_64) @r.architecture.should == :x86_64 @r.registry_system_architecture.should == 0x0100 end it "can correctly set the requested architecture to :machine" do @r = Chef::Win32::Registry.new(@run_context, :machine) @r.architecture.should == :machine @r.registry_system_architecture.should == 0x0100 end end context "architecture setter" do it "sets the requested architecture to 64-bit if passed 64-bit" do @registry.architecture = :x86_64 @registry.architecture.should == :x86_64 @registry.registry_system_architecture.should == 0x0100 end it "sets the requested architecture to :machine if passed :machine" do @registry.architecture = :machine @registry.architecture.should == :machine @registry.registry_system_architecture.should == 0x0100 end it "sets the requested architecture to 32-bit if passed 32-bit" do @registry.architecture = :i386 @registry.architecture.should == :i386 @registry.registry_system_architecture.should == 0x0200 end end end describe "when running on an actual 64-bit server", :windows64_only do before(:all) do begin ::Win32::Registry::HKEY_LOCAL_MACHINE.open("Software\\Root", ::Win32::Registry::KEY_ALL_ACCESS | 0x0100) do |reg| reg.delete_key("Trunk", true) end rescue end begin ::Win32::Registry::HKEY_LOCAL_MACHINE.open("Software\\Root", ::Win32::Registry::KEY_ALL_ACCESS | 0x0200) do |reg| reg.delete_key("Trunk", true) end rescue end # 64-bit ::Win32::Registry::HKEY_LOCAL_MACHINE.create("Software\\Root\\Mauve", ::Win32::Registry::KEY_ALL_ACCESS | 0x0100) ::Win32::Registry::HKEY_LOCAL_MACHINE.open('Software\\Root\\Mauve', Win32::Registry::KEY_ALL_ACCESS | 0x0100) do |reg| reg['Alert', Win32::Registry::REG_SZ] = 'Universal' end # 32-bit ::Win32::Registry::HKEY_LOCAL_MACHINE.create("Software\\Root\\Poosh", ::Win32::Registry::KEY_ALL_ACCESS | 0x0200) ::Win32::Registry::HKEY_LOCAL_MACHINE.open('Software\\Root\\Poosh', Win32::Registry::KEY_ALL_ACCESS | 0x0200) do |reg| reg['Status', Win32::Registry::REG_SZ] = 'Lost' end end after(:all) do ::Win32::Registry::HKEY_LOCAL_MACHINE.open("Software\\Root", ::Win32::Registry::KEY_ALL_ACCESS | 0x0100) do |reg| reg.delete_key("Trunk", true) end ::Win32::Registry::HKEY_LOCAL_MACHINE.open("Software\\Root", ::Win32::Registry::KEY_ALL_ACCESS | 0x0200) do |reg| reg.delete_key("Trunk", true) end end describe "key_exists?" do it "does not find 64-bit keys in the 32-bit registry" do @registry.architecture=:i386 @registry.key_exists?("HKLM\\Software\\Root\\Mauve").should == false end it "finds 32-bit keys in the 32-bit registry" do @registry.architecture=:i386 @registry.key_exists?("HKLM\\Software\\Root\\Poosh").should == true end it "does not find 32-bit keys in the 64-bit registry" do @registry.architecture=:x86_64 @registry.key_exists?("HKLM\\Software\\Root\\Mauve").should == true end it "finds 64-bit keys in the 64-bit registry" do @registry.architecture=:x86_64 @registry.key_exists?("HKLM\\Software\\Root\\Poosh").should == false end end describe "value_exists?" do it "does not find 64-bit values in the 32-bit registry" do @registry.architecture=:i386 lambda{@registry.value_exists?("HKLM\\Software\\Root\\Mauve", {:name=>"Alert"})}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end it "finds 32-bit values in the 32-bit registry" do @registry.architecture=:i386 @registry.value_exists?("HKLM\\Software\\Root\\Poosh", {:name=>"Status"}).should == true end it "does not find 32-bit values in the 64-bit registry" do @registry.architecture=:x86_64 @registry.value_exists?("HKLM\\Software\\Root\\Mauve", {:name=>"Alert"}).should == true end it "finds 64-bit values in the 64-bit registry" do @registry.architecture=:x86_64 lambda{@registry.value_exists?("HKLM\\Software\\Root\\Poosh", {:name=>"Status"})}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end end describe "data_exists?" do it "does not find 64-bit keys in the 32-bit registry" do @registry.architecture=:i386 lambda{@registry.data_exists?("HKLM\\Software\\Root\\Mauve", {:name=>"Alert", :type=>:string, :data=>"Universal"})}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end it "finds 32-bit keys in the 32-bit registry" do @registry.architecture=:i386 @registry.data_exists?("HKLM\\Software\\Root\\Poosh", {:name=>"Status", :type=>:string, :data=>"Lost"}).should == true end it "does not find 32-bit keys in the 64-bit registry" do @registry.architecture=:x86_64 @registry.data_exists?("HKLM\\Software\\Root\\Mauve", {:name=>"Alert", :type=>:string, :data=>"Universal"}).should == true end it "finds 64-bit keys in the 64-bit registry" do @registry.architecture=:x86_64 lambda{@registry.data_exists?("HKLM\\Software\\Root\\Poosh", {:name=>"Status", :type=>:string, :data=>"Lost"})}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) end end describe "create_key" do it "can create a 32-bit only registry key" do @registry.architecture = :i386 @registry.create_key("HKLM\\Software\\Root\\Trunk\\Red", true).should == true @registry.key_exists?("HKLM\\Software\\Root\\Trunk\\Red").should == true @registry.architecture = :x86_64 @registry.key_exists?("HKLM\\Software\\Root\\Trunk\\Red").should == false end it "can create a 64-bit only registry key" do @registry.architecture = :x86_64 @registry.create_key("HKLM\\Software\\Root\\Trunk\\Blue", true).should == true @registry.key_exists?("HKLM\\Software\\Root\\Trunk\\Blue").should == true @registry.architecture = :i386 @registry.key_exists?("HKLM\\Software\\Root\\Trunk\\Blue").should == false end end end end end chef-11.8.2/spec/functional/win32/service_manager_spec.rb0000644000004100000410000002065612254362222023300 0ustar www-datawww-data# # Author:: Serdar Sutay () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' if Chef::Platform.windows? require 'chef/application/windows_service_manager' end # # ATTENTION: # This test creates a windows service for testing purposes and runs it # as Local System on windows boxes. # This test will fail if you run the tests inside a Windows VM by # sharing the code from your host since Local System account by # default can't see the mounted partitions. # Run this test by copying the code to a local VM directory or setup # Local System account to see the maunted partitions for the shared # directories. # describe "Chef::Application::WindowsServiceManager", :windows_only, :system_windows_service_gem_only do # Some helper methods. def test_service_exists? ::Win32::Service.exists?("spec-service") end def test_service_state ::Win32::Service.status("spec-service").current_state end def service_manager Chef::Application::WindowsServiceManager.new(test_service) end def cleanup # Uninstall if the test service is installed. if test_service_exists? # We can only uninstall when the service is stopped. if test_service_state != "stopped" ::Win32::Service.send("stop", "spec-service") while test_service_state != "stopped" sleep 1 end end ::Win32::Service.delete("spec-service") end # Delete the test_service_file if it exists if File.exists?(test_service_file) File.delete(test_service_file) end end # Definition for the test-service let(:test_service) { { :service_name => "spec-service", :service_display_name => "Spec Test Service", :service_description => "Service for testing Chef::Application::WindowsServiceManager.", :service_file_path => File.expand_path(File.join(File.dirname(__FILE__), '../../support/platforms/win32/spec_service.rb')) } } # Test service creates a file for us to verify that it is running. # Since our test service is running as Local System we should look # for the file it creates under SYSTEM temp directory let(:test_service_file) { "#{ENV['SystemDrive']}\\windows\\temp\\spec_service_file" } context "with invalid service definition" do it "throws an error when initialized with no service definition" do lambda { Chef::Application::WindowsServiceManager.new(nil) }.should raise_error(ArgumentError) end it "throws an error with required missing options" do test_service.each do |key,value| service_def = test_service.dup service_def.delete(key) lambda { Chef::Application::WindowsServiceManager.new(service_def) }.should raise_error(ArgumentError) end end end context "with valid definition" do before(:each) do @service_manager_output = [ ] # Uncomment below lines to debug this test # original_puts = $stdout.method(:puts) $stdout.stub(:puts) do |message| @service_manager_output << message # original_puts.call(message) end end after(:each) do cleanup end context "when service doesn't exist" do it "default => should say service don't exist" do service_manager.run @service_manager_output.grep(/doesn't exist on the system/).length.should > 0 end it "install => should install the service" do service_manager.run(["-a", "install"]) test_service_exists?.should be_true end it "other actions => should say service doesn't exist" do ["delete", "start", "stop", "pause", "resume", "uninstall"].each do |action| service_manager.run(["-a", action]) @service_manager_output.grep(/doesn't exist on the system/).length.should > 0 @service_manager_output = [ ] end end end context "when service exists" do before(:each) do service_manager.run(["-a", "install"]) end it "install => should say service already exists" do service_manager.run(["-a", "install"]) @service_manager_output.grep(/already exists/).length.should > 0 end context "and service is stopped" do ["delete", "uninstall"].each do |action| it "#{action} => should remove the service", :volatile do service_manager.run(["-a", action]) test_service_exists?.should be_false end end it "default, status => should say service is stopped" do service_manager.run([ ]) @service_manager_output.grep(/stopped/).length.should > 0 @service_manager_output = [ ] service_manager.run(["-a", "status"]) @service_manager_output.grep(/stopped/).length.should > 0 end it "start should start the service", :volatile do service_manager.run(["-a", "start"]) test_service_state.should == "running" File.exists?(test_service_file).should be_true end it "stop should not affect the service" do service_manager.run(["-a", "stop"]) test_service_state.should == "stopped" end ["pause", "resume"].each do |action| it "#{action} => should raise error" do lambda {service_manager.run(["-a", action])}.should raise_error(::Win32::Service::Error) end end context "and service is started", :volatile do before(:each) do service_manager.run(["-a", "start"]) end ["delete", "uninstall"].each do |action| it "#{action} => should remove the service", :volatile do service_manager.run(["-a", action]) test_service_exists?.should be_false end end it "default, status => should say service is running" do service_manager.run([ ]) @service_manager_output.grep(/running/).length.should > 0 @service_manager_output = [ ] service_manager.run(["-a", "status"]) @service_manager_output.grep(/running/).length.should > 0 end it "stop should stop the service" do service_manager.run(["-a", "stop"]) test_service_state.should == "stopped" end it "pause should pause the service" do service_manager.run(["-a", "pause"]) test_service_state.should == "paused" end it "resume should have no affect" do service_manager.run(["-a", "resume"]) test_service_state.should == "running" end end context "and service is paused", :volatile do before(:each) do service_manager.run(["-a", "start"]) service_manager.run(["-a", "pause"]) end actions = ["delete", "uninstall"] actions.each do |action| it "#{action} => should remove the service" do service_manager.run(["-a", action]) test_service_exists?.should be_false end end it "default, status => should say service is paused" do service_manager.run([ ]) @service_manager_output.grep(/paused/).length.should > 0 @service_manager_output = [ ] service_manager.run(["-a", "status"]) @service_manager_output.grep(/paused/).length.should > 0 end it "stop should stop the service" do service_manager.run(["-a", "stop"]) test_service_state.should == "stopped" end it "pause should not affect the service" do service_manager.run(["-a", "pause"]) test_service_state.should == "paused" end it "start should raise an error" do lambda {service_manager.run(["-a", "start"])}.should raise_error(::Win32::Service::Error) end end end end end end chef-11.8.2/spec/functional/file_content_management/0000755000004100000410000000000012254362222022501 5ustar www-datawww-datachef-11.8.2/spec/functional/file_content_management/deploy_strategies_spec.rb0000644000004100000410000001511112254362222027565 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' shared_examples_for "a content deploy strategy" do # Ruby 1.8 has no binread def binread(file) if IO.respond_to?(:binread) IO.binread(file) else IO.read(file) end end def normalize_mode(mode_int) ( mode_int & 07777).to_s(8) end let(:sandbox_dir) do basename = make_tmpname("content-deploy-tests") full_path = File.join(CHEF_SPEC_DATA, basename) FileUtils.mkdir_p(full_path) full_path end after do FileUtils.rm_rf(sandbox_dir) if File.exist?(sandbox_dir) end let(:content_deployer) { described_class.new } let(:target_file_path) { File.join(sandbox_dir, "cp-deploy-strategy-target-file.txt") } describe "creating the file" do ## # UNIX Context let(:default_mode) { normalize_mode(0100666 - File.umask) } it "touches the file to create it (UNIX)", :unix_only do content_deployer.create(target_file_path) File.should exist(target_file_path) file_info = File.stat(target_file_path) file_info.should be_owned file_info.should be_file normalize_mode(file_info.mode).should == default_mode end ## # Window Context let(:parent_dir) { File.dirname(target_file_path) } let(:parent_security_descriptor) do security_obj = Chef::ReservedNames::Win32::Security::SecurableObject.new(parent_dir) security_obj.security_descriptor(true) end let(:masks) do Chef::ReservedNames::Win32::API::Security end def ace_inherits?(ace) flags = ace.flags (flags & masks::OBJECT_INHERIT_ACE) !=0 end let(:parent_inheritable_aces) do inheritable_aces = parent_security_descriptor.dacl.select do |ace| ace_inherits?(ace) end end # Win2003 has annoying differences in ACL inheritance behavior that make # the default ACLs substantially different from those created on subsequent # windows versions. The behaviors here are also covered by resource-level # tests so we'll skip win2k3 here to keep the tests simple. it "touches the file to create it (Windows)", :windows_only, :not_supported_on_win2k3 do content_deployer.create(target_file_path) File.should exist(target_file_path) file_info = File.stat(target_file_path) file_info.should be_owned file_info.should be_file parent_aces = parent_inheritable_aces security_obj = Chef::ReservedNames::Win32::Security::SecurableObject.new(target_file_path) security_descriptor = security_obj.security_descriptor(true) security_descriptor.dacl.each_with_index do |ace, index| ace.inherited?.should be_true ace.mask.should == parent_aces[index].mask end end end describe "updating the file" do let(:staging_dir) { Dir.mktmpdir } let(:staging_file_content) { "this is the expected content" } let(:staging_file_path) do path = File.join(staging_dir, "cp-deploy-strategy-staging-file.txt") File.open(path, "w+", 0600) { |f| f.print(staging_file_content) } path end def unix_invariant_properies(stat_struct) unix_invariants.inject({}) do |property_map, property| property_map[property] = stat_struct.send(property) property_map end end def win_invariant_properties(sec_obj) descriptor = sec_obj.security_descriptor(true) security_descriptor_invariants.inject({}) do |prop_map, property| prop_map[property] = descriptor.send(property) prop_map end end before do content_deployer.create(target_file_path) end it "maintains invariant properties on UNIX", :unix_only do original_info = File.stat(target_file_path) content_deployer.deploy(staging_file_path, target_file_path) updated_info = File.stat(target_file_path) unix_invariant_properies(original_info).should == unix_invariant_properies(updated_info) end it "maintains invariant properties on Windows", :windows_only do original_info = Chef::ReservedNames::Win32::Security::SecurableObject.new(target_file_path) content_deployer.deploy(staging_file_path, target_file_path) updated_info = Chef::ReservedNames::Win32::Security::SecurableObject.new(target_file_path) win_invariant_properties(original_info).should == win_invariant_properties(updated_info) end it "updates the target with content from staged" do content_deployer.deploy(staging_file_path, target_file_path) binread(target_file_path).should == staging_file_content end context "when the owner of the target file is not the owner of the staging file", :requires_root do before do File.chown(1337, 1337, target_file_path) end it "copies the staging file's content" do original_info = File.stat(target_file_path) content_deployer.deploy(staging_file_path, target_file_path) updated_info = File.stat(target_file_path) unix_invariant_properies(original_info).should == unix_invariant_properies(updated_info) end end end end describe Chef::FileContentManagement::Deploy::Cp do let(:unix_invariants) do [ :uid, :gid, :mode, :ino ] end let(:security_descriptor_invariants) do [ :owner, :group, :dacl ] end it_should_behave_like "a content deploy strategy" end describe Chef::FileContentManagement::Deploy::MvUnix, :unix_only do let(:unix_invariants) do [ :uid, :gid, :mode ] end it_should_behave_like "a content deploy strategy" end # On Unix we won't have loaded the file, avoid undefined constant errors: class Chef::FileContentManagement::Deploy::MvWindows ; end describe Chef::FileContentManagement::Deploy::MvWindows, :windows_only do context "when a file has no sacl" do let(:security_descriptor_invariants) do [ :owner, :group, :dacl ] end it_should_behave_like "a content deploy strategy" end end chef-11.8.2/spec/functional/provider/0000755000004100000410000000000012254362222017466 5ustar www-datawww-datachef-11.8.2/spec/functional/provider/remote_file/0000755000004100000410000000000012254362222021760 5ustar www-datawww-datachef-11.8.2/spec/functional/provider/remote_file/cache_control_data_spec.rb0000755000004100000410000000655012254362222027124 0ustar www-datawww-data# # Author:: Adam Edwards () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'uri' describe Chef::Provider::RemoteFile::CacheControlData do before do @original_config = Chef::Config.hash_dup end after do Chef::Config.configuration = @original_config if @original_config end before(:each) do Chef::Config[:file_cache_path] = Dir.mktmpdir end after(:each) do FileUtils.rm_rf(Chef::Config[:file_cache_path]) end let(:uri) { URI.parse("http://www.bing.com/robots.txt") } describe "when the cache control data save method is invoked" do subject(:cache_control_data) do Chef::Provider::RemoteFile::CacheControlData.load_and_validate(uri, file_checksum) end # the checksum of the file last we fetched it. let(:file_checksum) { "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" } let(:etag) { "\"a-strong-identifier\"" } let(:mtime) { "Thu, 01 Aug 2013 08:16:32 GMT" } before do cache_control_data.etag = etag cache_control_data.mtime = mtime cache_control_data.checksum = file_checksum end it "writes data to the cache" do cache_control_data.save end it "writes the data to the cache and the same data can be read back" do cache_control_data.save saved_cache_control_data = Chef::Provider::RemoteFile::CacheControlData.load_and_validate(uri, file_checksum) saved_cache_control_data.etag.should == cache_control_data.etag saved_cache_control_data.mtime.should == cache_control_data.mtime saved_cache_control_data.checksum.should == cache_control_data.checksum end # Cover the very long remote file path case -- see CHEF-4422 where # local cache file names generated from the long uri exceeded # local file system path limits resulting in exceptions from # file system API's on both Windows and Unix systems. context "when the length of the uri exceeds the path length limits for the local file system" do let(:uri_exceeds_file_system_limit) do URI.parse("http://www.bing.com/" + ('0' * 1024)) end let(:uri) { uri_exceeds_file_system_limit } it "writes data to the cache" do lambda do cache_control_data.save end.should_not raise_error end it "writes the data to the cache and the same data can be read back" do cache_control_data.save saved_cache_control_data = Chef::Provider::RemoteFile::CacheControlData.load_and_validate(uri, file_checksum) saved_cache_control_data.etag.should == cache_control_data.etag saved_cache_control_data.mtime.should == cache_control_data.mtime saved_cache_control_data.checksum.should == cache_control_data.checksum end end end end chef-11.8.2/spec/functional/assets/0000755000004100000410000000000012254362222017136 5ustar www-datawww-datachef-11.8.2/spec/functional/assets/dummy-2-0.aix6.1.noarch.rpm0000644000004100000410000000171412254362222023566 0ustar www-datawww-datadummy-2-0$ݽ6`}4Dd   48LPes (89:b&d8e=fBCdummy20dummy packageThis is a dummy package.QLlpar10ml16ed_pubDummies IncorporatedDummy LicenseLuciano Rocha Networking/Daemonshttp://www.dontbeadummy.org/aix6.1noarchdummy-2-0.src.rpm|3.0.5C Luciano Rocha 0- dummy-O2 -fsigned-charcpiogzip93070704 $!A>A @5|chef-11.8.2/spec/functional/assets/dummy-1-0.aix6.1.noarch.rpm0000644000004100000410000000171412254362222023565 0ustar www-datawww-datadummy-1-0$TOZ;X0gp#/Dd   48LPes (89:b&d8e=fBCdummy10dummy packageThis is a dummy package.Qlpar10ml16ed_pubDummies IncorporatedDummy LicenseLuciano Rocha Networking/Daemonshttp://www.dontbeadummy.org/aix6.1noarchdummy-1-0.src.rpm|3.0.5C Luciano Rocha 0- dummy-O2 -fsigned-charcpiogzip93070704 $!A>A @5|chef-11.8.2/spec/functional/assets/mytest-2.0-1.noarch.rpm0000644000004100000410000000414512254362222023113 0ustar www-datawww-datamytest-2.0-1T>D ,0@d1354e1297e641203ccab95d9556699a84e59639Mm`-c[3>5V?Fd    HLpt x    2 4<FPhpx(>GHIXY\]^!b4defkltuvwx{Cmytest2.01A test ScriptA test script inside a simple RPM packageQkaustubh-centos5-64-cron.opscode.usMITUtilitieshttp://www.oracle-base.com/articles/linux/linux-build-simple-rpm-packages.phplinuxnoarchchmod 755 -R /opt/mytestAQQfc457c3017d6f95b0876c7ebb6f58fcdrootrootrootrootmytest-2.0-1.src.rpmmytest@JJ/bin/shrpmlib(CompressedFileNames)rpmlib(PayloadFilesHavePrefix)3.0.4-14.0-14.4.2.3/bin/shldle2.0-1mytestmytest.sh/opt//opt/mytest/-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=genericcpiogzip9noarchnoarch-redhat-linux-gnuASCII textdirectorysystem_u:object_r:usr_t:s0system_u:object_r:usr_t:s0?30707040004K63&)؁aZApZ~7OO?D?$nSn Q6L&nCslvC)  HMWP ,Vļ"%.ĪCI0FHk"].X@chef-11.8.2/spec/functional/assets/PkgA.1.0.0.0.bff0000644000004100000410000000700012254362222021225 0ustar www-datawww-data kSQSQby nameby namerootd kyASQSQSQ ./n/A kySQSQSQ ./lpp_nameem4 R I PkgA { PkgA.rte 1.0.0.0 01 N U en_US My runtime fileset [ % /usr/PkgA 0 /usr/PkgA/bin 8 /usr/doc/PkgA 8 /usr/lib/objrepos 5 INSTWORK 16 16 % % % % % ] } kRMARQSQSQ ./usraA k$QASQSQSQ ./usr/lpppA k^ASQSQSQ ./usr/lpp/PkgA/pA k`2\SQSQSQ \./usr/lpp/PkgA/liblpp.a/p 1444 0 68 1258 0 87 260 0 1375425475 0 0 644 11 PkgA.rte.al` ./usr/doc/PkgA ./usr/doc/PkgA/README ./usr/PkgA ./usr/PkgA/bin ./usr/PkgA/bin/acommand 887 1258 68 1375425475 0 0 644 18 PkgA.rte.inventory` /usr/doc/PkgA: owner = root group = system mode = 755 type = DIRECTORY class = apply,inventory,PkgA.rte /usr/doc/PkgA/README: owner = root group = system mode = 644 type = FILE class = apply,inventory,PkgA.rte size = 24 checksum = "08645 1 " /usr/PkgA: owner = root group = system mode = 755 type = DIRECTORY class = apply,inventory,PkgA.rte /usr/PkgA/bin: owner = root group = system mode = 755 type = DIRECTORY class = apply,inventory,PkgA.rte /usr/PkgA/bin/acommand: owner = root group = system mode = 744 type = FILE class = apply,inventory,PkgA.rte size = 42 checksum = "23244 1 " 79 1444 260 1375425475 0 0 644 13 PkgA.rte.size` /usr/PkgA 0 /usr/PkgA/bin 8 /usr/doc/PkgA 8 /usr/lib/objrepos 5 INSTWORK 16 16 93 0 1258 0 0 0 0 0 ` 3 68 260 1258 PkgA.rte.alPkgA.rte.inventoryPkgA.rte.size kAfSQRQRQ ./usr/doc/PkgA/cA kSQnSQnSQ ./usr/doc/PkgA/README/cThis is the PkgA README kꨣA4SQ8SQ8SQ ./usr/PkgAgA/RAgA k꾇A8SQASQASQ ./usr/PkgA/binAgA k꬚*SQUSQYSQ *./usr/PkgA/bin/acommandAg#!/bin/sh echo "Here is my PkgA command" 1258k ./usr/doc/PkgA/README/cThis is the PkgA README kꨣA4SQ8SQ8SQ ./usr/PkgAgA/RAgA k꾇A8SQASQASQ ./usr/PkgA/binAgchef-11.8.2/spec/functional/assets/PkgA.2.0.0.0.bff0000644000004100000410000000700012254362222021226 0ustar www-datawww-data k8kQkQby nameby namerootd k AkQkQkQ ./n/A kkQkQkQ ./lpp_nameem4 R I PkgA { PkgA.rte 2.0.0.0 01 N U en_US My runtime fileset [ % /usr/PkgA 0 /usr/PkgA/bin 8 /usr/doc/PkgA 8 /usr/lib/objrepos 5 INSTWORK 16 16 % % % % % ] } k@yAkQSQSQ ./usraA k$QASQSQSQ ./usr/lpppA kꮄASQkQkQ ./usr/lpp/PkgA/pA kؠ\kQkQkQ \./usr/lpp/PkgA/liblpp.a/p 1444 0 68 1258 0 87 260 0 1375431679 0 0 644 11 PkgA.rte.al` ./usr/doc/PkgA ./usr/doc/PkgA/README ./usr/PkgA ./usr/PkgA/bin ./usr/PkgA/bin/acommand 887 1258 68 1375431679 0 0 644 18 PkgA.rte.inventory` /usr/doc/PkgA: owner = root group = system mode = 755 type = DIRECTORY class = apply,inventory,PkgA.rte /usr/doc/PkgA/README: owner = root group = system mode = 644 type = FILE class = apply,inventory,PkgA.rte size = 24 checksum = "08645 1 " /usr/PkgA: owner = root group = system mode = 755 type = DIRECTORY class = apply,inventory,PkgA.rte /usr/PkgA/bin: owner = root group = system mode = 755 type = DIRECTORY class = apply,inventory,PkgA.rte /usr/PkgA/bin/acommand: owner = root group = system mode = 744 type = FILE class = apply,inventory,PkgA.rte size = 46 checksum = "62939 1 " 79 1444 260 1375431679 0 0 644 13 PkgA.rte.size` /usr/PkgA 0 /usr/PkgA/bin 8 /usr/doc/PkgA 8 /usr/lib/objrepos 5 INSTWORK 16 16 93 0 1258 0 0 0 0 0 ` 3 68 260 1258 PkgA.rte.alPkgA.rte.inventoryPkgA.rte.size kAfSQRQRQ ./usr/doc/PkgA/cA k.kQnSQnSQ ./usr/doc/PkgA/README/cThis is the PkgA README kꨢAkQ8SQ8SQ ./usr/PkgAgA/RAgA kꨉAkQASQASQ ./usr/PkgA/binAgA k&.kQkQkQ ../usr/PkgA/bin/acommandAg#!/bin/sh echo "Here is my PkgA command 2.0" 58k ./usr/doc/PkgA/README/cThis is the PkgA README kꨢAkQ8SQ8SQ ./usr/PkgAgA/RAgA kꨉAkQASQASQ ./usr/PkgA/binAgchef-11.8.2/spec/functional/assets/mytest-1.0-1.noarch.rpm0000644000004100000410000000411612254362222023110 0ustar www-datawww-datamytest-1.0-1T>D ,0@f613507b95c6c5a51d7aec52373784dd2b49f4916sS &k>5F?6d    HL`d hr    " $,6@X`ht(>GHIXY\]^b$defkltuvwx{Cmytest1.01A test scriptA test script inside a simple RPM packageQbPrabhu1.localdomainMITUtilitieshttp://www.oracle-base.com/articles/linux/linux-build-simple-rpm-packages.phplinuxnoarchchmod 755 -R /opt/mytestAQbQb4cdc303079a9a328fb74f7dfc01e2008rootrootrootrootmytest-1.0-1.src.rpmmytest@JJ/bin/shrpmlib(CompressedFileNames)rpmlib(PayloadFilesHavePrefix)3.0.4-14.0-14.4.2.3/bin/sh''1.0-1mytestmytest.sh/opt//opt/mytest/-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=genericcpiogzip9noarchnoarch-redhat-linux-gnuASCII textdirectorysystem_u:object_r:usr_t:s0system_u:object_r:usr_t:s0?307070400L120102 U8 zV00 m m!݆fmhn(W J! @RB(@:tː GO EEE(echef-11.8.2/spec/functional/tiny_server_spec.rb0000644000004100000410000000526012254362222021547 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'tiny_server' describe TinyServer::API do before do @api = TinyServer::API.instance @api.clear end it "is a Singleton" do lambda {TinyServer::API.new}.should raise_error end it "clears the router" do @api.get('/blargh', 200, "blargh") @api.clear @api.routes["GET"].should be_empty end it "creates a route for a GET request" do @api.get('/foo/bar', 200, 'hello foobar') # WEBrick gives you the full URI with host, Thin only gave the part after scheme+host+port response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => 'http://localhost:1974/foo/bar') response.should == [200, {'Content-Type' => 'application/json'}, [ 'hello foobar' ]] end it "creates a route for a request with a block" do block_called = false @api.get('/bar/baz', 200) { block_called = true; 'hello barbaz' } response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => 'http://localhost:1974/bar/baz') response.should == [200, {'Content-Type' => 'application/json'}, [ 'hello barbaz' ]] block_called.should be_true end it "returns debugging info for 404s" do response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => '/no_such_thing') response[0].should == 404 response[1].should == {'Content-Type' => 'application/json'} response[2].should be_a_kind_of(String) response_obj = Chef::JSONCompat.from_json(response[2]) response_obj["message"].should == "no data matches the request for /no_such_thing" response_obj["available_routes"].should == {"GET"=>[], "PUT"=>[], "POST"=>[], "DELETE"=>[]} response_obj["request"].should == {"REQUEST_METHOD"=>"GET", "REQUEST_URI"=>"/no_such_thing"} end end describe TinyServer::Manager do it "runs the server" do @server = TinyServer::Manager.new @server.start TinyServer::API.instance.get("/index", 200, "[\"hello\"]") rest = Chef::REST.new('http://localhost:9000', false, false) rest.get_rest("index").should == ["hello"] @server.stop end end chef-11.8.2/spec/functional/knife/0000755000004100000410000000000012254362222016730 5ustar www-datawww-datachef-11.8.2/spec/functional/knife/ssh_spec.rb0000644000004100000410000001724612254362222021076 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'tiny_server' describe Chef::Knife::Ssh do before(:all) do Chef::Knife::Ssh.load_deps @server = TinyServer::Manager.new @server.start end after(:all) do @server.stop end describe "identity file" do context "when knife[:ssh_identity_file] is set" do before do setup_knife(['*:*', 'uptime']) Chef::Config[:knife][:ssh_identity_file] = "~/.ssh/aws.rsa" end it "uses the ssh_identity_file" do @knife.run @knife.config[:identity_file].should == "~/.ssh/aws.rsa" end end context "when knife[:ssh_identity_file] is set and frozen" do before do setup_knife(['*:*', 'uptime']) Chef::Config[:knife][:ssh_identity_file] = "~/.ssh/aws.rsa".freeze end it "uses the ssh_identity_file" do @knife.run @knife.config[:identity_file].should == "~/.ssh/aws.rsa" end end context "when -i is provided" do before do setup_knife(['-i ~/.ssh/aws.rsa', '*:*', 'uptime']) Chef::Config[:knife][:ssh_identity_file] = nil end it "should use the value on the command line" do @knife.run @knife.config[:identity_file].should == "~/.ssh/aws.rsa" end it "should override what is set in knife.rb" do Chef::Config[:knife][:ssh_identity_file] = "~/.ssh/other.rsa" @knife.run @knife.config[:identity_file].should == "~/.ssh/aws.rsa" end end context "when knife[:ssh_identity_file] is not provided]" do before do setup_knife(['*:*', 'uptime']) Chef::Config[:knife][:ssh_identity_file] = nil end it "uses the default" do @knife.run @knife.config[:identity_file].should == nil end end end describe "port" do context "when -p 31337 is provided" do before do setup_knife(['-p 31337', '*:*', 'uptime']) end it "uses the ssh_port" do @knife.run @knife.config[:ssh_port].should == "31337" end end end describe "user" do context "when knife[:ssh_user] is set" do before do setup_knife(['*:*', 'uptime']) Chef::Config[:knife][:ssh_user] = "ubuntu" end it "uses the ssh_user" do @knife.run @knife.config[:ssh_user].should == "ubuntu" end end context "when knife[:ssh_user] is set and frozen" do before do setup_knife(['*:*', 'uptime']) Chef::Config[:knife][:ssh_user] = "ubuntu".freeze end it "uses the ssh_user" do @knife.run @knife.config[:ssh_user].should == "ubuntu" end end context "when -x is provided" do before do setup_knife(['-x ubuntu', '*:*', 'uptime']) Chef::Config[:knife][:ssh_user] = nil end it "should use the value on the command line" do @knife.run @knife.config[:ssh_user].should == "ubuntu" end it "should override what is set in knife.rb" do Chef::Config[:knife][:ssh_user] = "root" @knife.run @knife.config[:ssh_user].should == "ubuntu" end end context "when knife[:ssh_user] is not provided]" do before do setup_knife(['*:*', 'uptime']) Chef::Config[:knife][:ssh_user] = nil end it "uses the default (current user)" do @knife.run @knife.config[:ssh_user].should == nil end end end describe "attribute" do context "when knife[:ssh_attribute] is set" do before do setup_knife(['*:*', 'uptime']) Chef::Config[:knife][:ssh_attribute] = "ec2.public_hostname" end it "uses the ssh_attribute" do @knife.run @knife.config[:attribute].should == "ec2.public_hostname" end end context "when knife[:ssh_attribute] is not provided]" do before do setup_knife(['*:*', 'uptime']) Chef::Config[:knife][:ssh_attribute] = nil end it "uses the default" do @knife.run @knife.config[:attribute].should == "fqdn" end end context "when -a ec2.public_ipv4 is provided" do before do setup_knife(['-a ec2.public_hostname', '*:*', 'uptime']) Chef::Config[:knife][:ssh_attribute] = nil end it "should use the value on the command line" do @knife.run @knife.config[:attribute].should == "ec2.public_hostname" end it "should override what is set in knife.rb" do # This is the setting imported from knife.rb Chef::Config[:knife][:ssh_attribute] = "fqdn" # Then we run knife with the -a flag, which sets the above variable setup_knife(['-a ec2.public_hostname', '*:*', 'uptime']) @knife.run @knife.config[:attribute].should == "ec2.public_hostname" end end end describe "gateway" do context "when knife[:ssh_gateway] is set" do before do setup_knife(['*:*', 'uptime']) Chef::Config[:knife][:ssh_gateway] = "user@ec2.public_hostname" end it "uses the ssh_gateway" do @knife.session.should_receive(:via).with("ec2.public_hostname", "user", {}) @knife.run @knife.config[:ssh_gateway].should == "user@ec2.public_hostname" end end context "when -G user@ec2.public_hostname is provided" do before do setup_knife(['-G user@ec2.public_hostname', '*:*', 'uptime']) Chef::Config[:knife][:ssh_gateway] = nil end it "uses the ssh_gateway" do @knife.session.should_receive(:via).with("ec2.public_hostname", "user", {}) @knife.run @knife.config[:ssh_gateway].should == "user@ec2.public_hostname" end end context "when the gateway requires a password" do before do setup_knife(['-G user@ec2.public_hostname', '*:*', 'uptime']) Chef::Config[:knife][:ssh_gateway] = nil @knife.session.stub(:via) do |host, user, options| raise Net::SSH::AuthenticationFailed unless options[:password] end end it "should prompt the user for a password" do @knife.ui.should_receive(:ask).with("Enter the password for user@ec2.public_hostname: ").and_return("password") @knife.run end end end def setup_knife(params=[]) @knife = Chef::Knife::Ssh.new(params) # We explicitly avoid running #configure_chef, which would read a knife.rb # if available, but #merge_configs (which is called by #configure_chef) is # necessary to have default options merged in. @knife.merge_configs @knife.stub!(:ssh_command).and_return { 0 } @api = TinyServer::API.instance @api.clear Chef::Config[:node_name] = nil Chef::Config[:client_key] = nil Chef::Config[:chef_server_url] = 'http://localhost:9000' @api.get("/search/node?q=*:*&sort=X_CHEF_id_CHEF_X%20asc&start=0&rows=1000", 200) { %({"total":1, "start":0, "rows":[{"name":"i-xxxxxxxx", "json_class":"Chef::Node", "automatic":{"fqdn":"the.fqdn", "ec2":{"public_hostname":"the_public_hostname"}},"recipes":[]}]}) } end end chef-11.8.2/spec/functional/knife/smoke_test.rb0000644000004100000410000000233412254362222021434 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' describe "knife smoke tests" do # Since our specs load all code, there could be a case where knife does not # run correctly b/c of a missing require, but is not caught by other tests. # # We run `knife -v` to verify that knife at least loads all its code. it "can run and print its version" do knife_path = File.expand_path("../../bin/knife", CHEF_SPEC_DATA) knife_cmd = Mixlib::ShellOut.new("#{knife_path} -v") knife_cmd.run_command knife_cmd.error! knife_cmd.stdout.should include(Chef::VERSION) end end chef-11.8.2/spec/functional/knife/cookbook_delete_spec.rb0000644000004100000410000001276212254362222023427 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'tiny_server' describe Chef::Knife::CookbookDelete do before(:all) do @server = TinyServer::Manager.new @server.start end before(:each) do @knife = Chef::Knife::CookbookDelete.new @api = TinyServer::API.instance @api.clear Chef::Config[:node_name] = nil Chef::Config[:client_key] = nil Chef::Config[:chef_server_url] = 'http://localhost:9000' end after(:all) do @server.stop end context "when the cookbook doesn't exist" do before do @log_output = StringIO.new Chef::Log.logger = Logger.new(@log_output) Chef::Log.level = :debug @knife.name_args = %w{no-such-cookbook} @api.get("/cookbooks/no-such-cookbook", 404, {'error'=>'dear Tim, no. -Sent from my iPad'}.to_json) end it "logs an error and exits" do @knife.ui.stub!(:stderr).and_return(@log_output) lambda {@knife.run}.should raise_error(SystemExit) @log_output.string.should match(/Cannot find a cookbook named no-such-cookbook to delete/) end end context "when there is only one version of a cookbook" do before do @knife.name_args = %w{obsolete-cookbook} @cookbook_list = {'obsolete-cookbook' => { 'versions' => ['version' => '1.0.0']} } @api.get("/cookbooks/obsolete-cookbook", 200, @cookbook_list.to_json) end it "asks for confirmation, then deletes the cookbook" do stdin, stdout = StringIO.new("y\n"), StringIO.new @knife.ui.stub!(:stdin).and_return(stdin) @knife.ui.stub!(:stdout).and_return(stdout) cb100_deleted = false @api.delete("/cookbooks/obsolete-cookbook/1.0.0", 200) { cb100_deleted = true; "[\"true\"]" } @knife.run stdout.string.should match(/#{Regexp.escape('Do you really want to delete obsolete-cookbook version 1.0.0? (Y/N)')}/) cb100_deleted.should be_true end it "asks for confirmation before purging" do @knife.config[:purge] = true stdin, stdout = StringIO.new("y\ny\n"), StringIO.new @knife.ui.stub!(:stdin).and_return(stdin) @knife.ui.stub!(:stdout).and_return(stdout) cb100_deleted = false @api.delete("/cookbooks/obsolete-cookbook/1.0.0?purge=true", 200) { cb100_deleted = true; "[\"true\"]" } @knife.run stdout.string.should match(/#{Regexp.escape('Are you sure you want to purge files')}/) stdout.string.should match(/#{Regexp.escape('Do you really want to delete obsolete-cookbook version 1.0.0? (Y/N)')}/) cb100_deleted.should be_true end end context "when there are several versions of a cookbook" do before do @knife.name_args = %w{obsolete-cookbook} versions = ['1.0.0', '1.1.0', '1.2.0'] with_version = lambda { |version| { 'version' => version } } @cookbook_list = {'obsolete-cookbook' => { 'versions' => versions.map(&with_version) } } @api.get("/cookbooks/obsolete-cookbook", 200, @cookbook_list.to_json) end it "deletes all versions of a cookbook when given the '-a' flag" do @knife.config[:all] = true @knife.config[:yes] = true cb100_deleted = cb110_deleted = cb120_deleted = nil @api.delete("/cookbooks/obsolete-cookbook/1.0.0", 200) { cb100_deleted = true; "[\"true\"]" } @api.delete("/cookbooks/obsolete-cookbook/1.1.0", 200) { cb110_deleted = true; "[\"true\"]" } @api.delete("/cookbooks/obsolete-cookbook/1.2.0", 200) { cb120_deleted = true; "[\"true\"]" } @knife.run cb100_deleted.should be_true cb110_deleted.should be_true cb120_deleted.should be_true end it "asks which version to delete and deletes that when not given the -a flag" do cb100_deleted = cb110_deleted = cb120_deleted = nil @api.delete("/cookbooks/obsolete-cookbook/1.0.0", 200) { cb100_deleted = true; "[\"true\"]" } stdin, stdout = StringIO.new, StringIO.new @knife.ui.stub!(:stdin).and_return(stdin) @knife.ui.stub!(:stdout).and_return(stdout) stdin << "1\n" stdin.rewind @knife.run cb100_deleted.should be_true stdout.string.should match(/Which version\(s\) do you want to delete\?/) end it "deletes all versions of the cookbook when not given the -a flag and the user chooses to delete all" do cb100_deleted = cb110_deleted = cb120_deleted = nil @api.delete("/cookbooks/obsolete-cookbook/1.0.0", 200) { cb100_deleted = true; "[\"true\"]" } @api.delete("/cookbooks/obsolete-cookbook/1.1.0", 200) { cb110_deleted = true; "[\"true\"]" } @api.delete("/cookbooks/obsolete-cookbook/1.2.0", 200) { cb120_deleted = true; "[\"true\"]" } stdin, stdout = StringIO.new("4\n"), StringIO.new @knife.ui.stub!(:stdin).and_return(stdin) @knife.ui.stub!(:stdout).and_return(stdout) @knife.run cb100_deleted.should be_true cb110_deleted.should be_true cb120_deleted.should be_true end end end chef-11.8.2/spec/functional/knife/exec_spec.rb0000644000004100000410000000321412254362222021213 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'spec_helper' require 'tiny_server' describe Chef::Knife::Exec do before(:all) do @server = TinyServer::Manager.new#(:debug => true) @server.start end before(:each) do @knife = Chef::Knife::Exec.new @api = TinyServer::API.instance @api.clear Chef::Config[:node_name] = nil Chef::Config[:client_key] = nil Chef::Config[:chef_server_url] = 'http://localhost:9000' $output = StringIO.new end after(:all) do @server.stop end pending "executes a script in the context of the chef-shell main context", :ruby_18_only it "executes a script in the context of the chef-shell main context", :ruby_gte_19_only do @node = Chef::Node.new @node.name("ohai-world") response = {"rows" => [@node],"start" => 0,"total" => 1} @api.get(%r{^/search/node}, 200, response.to_json) code = "$output.puts nodes.all" @knife.config[:exec] = code @knife.run $output.string.should match(%r{node\[ohai-world\]}) end end chef-11.8.2/spec/functional/dsl/0000755000004100000410000000000012254362222016416 5ustar www-datawww-datachef-11.8.2/spec/functional/dsl/registry_helper_spec.rb0000644000004100000410000000510512254362222023165 0ustar www-datawww-data# # Author:: Prajakta Purohit () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require "chef/dsl/registry_helper" require "spec_helper" describe Chef::Resource::RegistryKey, :windows_only do before (:all) do ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root" ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Branch" ::Win32::Registry::HKEY_CURRENT_USER.open('Software\\Root', Win32::Registry::KEY_ALL_ACCESS) do |reg| reg['RootType1', Win32::Registry::REG_SZ] = 'fibrous' reg.write('Roots', Win32::Registry::REG_MULTI_SZ, ["strong roots", "healthy tree"]) end events = Chef::EventDispatch::Dispatcher.new node = Chef::Node.new ohai = Ohai::System.new ohai.all_plugins node.consume_external_attrs(ohai.data,{}) run_context = Chef::RunContext.new(node, {}, events) @resource = Chef::Resource.new("foo", run_context) end context "tests registry dsl" do it "returns true if registry_key_exists" do @resource.registry_key_exists?("HKCU\\Software\\Root").should == true end it "returns true if registry has specified value" do values = @resource.registry_get_values("HKCU\\Software\\Root") values.include?({:name=>"RootType1",:type=>:string,:data=>"fibrous"}).should == true end it "returns true if specified registry_has_subkey" do @resource.registry_has_subkeys?("HKCU\\Software\\Root").should == true end it "returns true if specified key has specified subkey" do subkeys = @resource.registry_get_subkeys("HKCU\\Software\\Root") subkeys.include?("Branch").should == true end it "returns true if registry_value_exists" do @resource.registry_value_exists?("HKCU\\Software\\Root", {:name=>"RootType1", :type=>:string, :data=>"fibrous"}).should == true end it "returns true if data_value_exists" do @resource.registry_data_exists?("HKCU\\Software\\Root", {:name=>"RootType1", :type=>:string, :data=>"fibrous"}).should == true end end end chef-11.8.2/spec/functional/run_lock_spec.rb0000644000004100000410000001657612254362222021026 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require File.expand_path('../../spec_helper', __FILE__) require 'chef/client' describe Chef::RunLock do # This behavior works on windows, but the tests use fork :( describe "when locking the chef-client run", :unix_only => true do ## # Lockfile location and helpers let(:random_temp_root) do Kernel.srand(Time.now.to_i + Process.pid) "/tmp/#{Kernel.rand(Time.now.to_i + Process.pid)}" end let(:lockfile){ "#{random_temp_root}/this/long/path/does/not/exist/chef-client-running.pid" } # make sure to start with a clean slate. before(:each){ FileUtils.rm_r(random_temp_root) if File.exist?(random_temp_root) } after(:each){ FileUtils.rm_r(random_temp_root) } def wait_on_lock tries = 0 until File.exist?(lockfile) raise "Lockfile never created, abandoning test" if tries > 10 tries += 1 sleep 0.1 end end ## # Side channel via a pipe allows child processes to send errors to the parent # Don't lazy create the pipe or else we might not share it with subprocesses let!(:error_pipe) do r,w = IO.pipe w.sync = true [r,w] end let(:error_read) { error_pipe[0] } let(:error_write) { error_pipe[1] } after do error_read.close unless error_read.closed? error_write.close unless error_write.closed? end # Send a RuntimeError from the child process to the parent process. Also # prints error to $stdout, just in case something goes wrong with the error # marshaling stuff. def send_side_channel_error(message) $stderr.puts(message) $stderr.puts(caller) e = RuntimeError.new(message) error_write.print(Marshal.dump(e)) end # Read the error (if any) from the error channel. If a marhaled error is # present, it is unmarshaled and raised (which will fail the test) def raise_side_channel_error! error_write.close err = error_read.read error_read.close begin # ArgumentError from Marshal.load indicates no data, which we assume # means no error in child process. raise Marshal.load(err) rescue ArgumentError nil end end ## # Interprocess synchronization via a pipe. This allows us to control the # state of the processes competing over the lock without relying on sleep. let!(:sync_pipe) do r,w = IO.pipe w.sync = true [r,w] end let(:sync_read) { sync_pipe[0] } let(:sync_write) { sync_pipe[1] } after do sync_read.close unless sync_read.closed? sync_write.close unless sync_write.closed? end # Wait on synchronization signal. If not received within the timeout, an # error is sent via the error channel, and the process exits. def sync_wait if IO.select([sync_read], nil, nil, 20).nil? # timeout reading from the sync pipe. send_side_channel_error("Error syncing processes in run lock test (timeout)") exit!(1) else sync_read.getc end end # Sends a character in the sync pipe, which wakes ("unlocks") another # process that is waiting on the sync signal def sync_send sync_write.putc("!") sync_write.flush end ## # IPC to record test results in a pipe. Tests can read pipe contents to # check that operations occur in the expected order. let!(:results_pipe) do r,w = IO.pipe w.sync = true [r,w] end let(:results_read) { results_pipe[0] } let(:results_write) { results_pipe[1] } after do results_read.close unless results_read.closed? results_write.close unless results_write.closed? end # writes the message to the results pipe for later checking. # note that nothing accounts for the pipe filling and waiting forever on a # read or write call, so don't put too much data in. def record(message) results_write.puts(message) results_write.flush end def results results_write.flush results_write.close message = results_read.read results_read.close message end ## # Run lock is the system under test let!(:run_lock) { Chef::RunLock.new(lockfile) } it "creates the full path to the lockfile" do lambda { run_lock.acquire }.should_not raise_error(Errno::ENOENT) File.should exist(lockfile) end it "sets FD_CLOEXEC on the lockfile", :supports_cloexec => true do run_lock.acquire (run_lock.runlock.fcntl(Fcntl::F_GETFD, 0) & Fcntl::FD_CLOEXEC).should == Fcntl::FD_CLOEXEC end it "allows only one chef client run per lockfile" do # First process, gets the lock and keeps it. p1 = fork do run_lock.acquire record "p1 has lock" # Wait until the other process is trying to get the lock: sync_wait # sleep a little bit to make process p2 wait on the lock sleep 2 record "p1 releasing lock" run_lock.release exit!(0) end # Wait until p1 creates the lockfile wait_on_lock p2 = fork do # inform process p1 that we're trying to get the lock sync_send run_lock.acquire record "p2 has lock" run_lock.release exit!(0) end Process.waitpid2(p1) Process.waitpid2(p2) raise_side_channel_error! expected=<<-E p1 has lock p1 releasing lock p2 has lock E results.should == expected end it "clears the lock if the process dies unexpectedly" do p1 = fork do run_lock.acquire record "p1 has lock" sleep 60 record "p1 still has lock" exit! 1 end wait_on_lock Process.kill(:KILL, p1) Process.waitpid2(p1) p2 = fork do run_lock.acquire record "p2 has lock" run_lock.release exit! 0 end Process.waitpid2(p2) results.should =~ /p2 has lock\Z/ end it "test returns true and acquires the lock" do p1 = fork do run_lock.test.should == true sleep 2 exit! 1 end wait_on_lock p2 = fork do run_lock.test.should == false exit! 0 end Process.waitpid2(p2) Process.waitpid2(p1) end it "test returns without waiting when the lock is acquired" do p1 = fork do run_lock.acquire sleep 2 exit! 1 end wait_on_lock run_lock.test.should == false Process.waitpid2(p1) end it "doesn't truncate the lock file so that contents can be read" do p1 = fork do run_lock.acquire run_lock.save_pid sleep 2 exit! 1 end wait_on_lock File.read(lockfile).should == p1.to_s Process.waitpid2(p1) end end end chef-11.8.2/spec/functional/shell_spec.rb0000644000004100000410000000767112254362222020315 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'functional/resource/base' require 'chef/version' require 'chef/shell' require 'chef/mixin/command/unix' describe Shell do # chef-shell's unit tests are by necessity very mock-heavy, and frequently do # not catch cases where chef-shell fails to boot because of changes in # chef/client.rb describe "smoke tests", :unix_only => true do include Chef::Mixin::Command::Unix def read_until(io, expected_value) start = Time.new buffer = "" until buffer.include?(expected_value) begin buffer << io.read_nonblock(1) rescue Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::EIO, EOFError sleep 0.01 end if Time.new - start > 30 STDERR.puts "did not read expected value `#{expected_value}' within 15s" STDERR.puts "Buffer so far: `#{buffer}'" break end end buffer end def wait_or_die(pid) start = Time.new until exitstatus = Process.waitpid2(pid, Process::WNOHANG) if Time.new - start > 5 STDERR.puts("chef-shell tty did not exit cleanly, killing it") Process.kill(:KILL, pid) end sleep 0.01 end exitstatus[1] end def run_chef_shell_with(options) case ohai[:platform] when "aix" config = File.expand_path("shef-config.rb", CHEF_SPEC_DATA) path_to_chef_shell = File.expand_path("../../../bin/chef-shell", __FILE__) output = '' status = popen4("#{path_to_chef_shell} -c #{config} #{options}", :waitlast => true) do |pid, stdin, stdout, stderr| read_until(stdout, "chef >") yield stdout, stdin if block_given? stdin.write("'done'\n") output = read_until(stdout, '=> "done"') stdin.print("exit\n") read_until(stdout, "\n") end [output, status.exitstatus] else # Windows ruby installs don't (always?) have PTY, # so hide the require here begin require 'pty' config = File.expand_path("shef-config.rb", CHEF_SPEC_DATA) path_to_chef_shell = File.expand_path("../../../bin/chef-shell", __FILE__) reader, writer, pid = PTY.spawn("#{path_to_chef_shell} -c #{config} #{options}") read_until(reader, "chef >") yield reader, writer if block_given? writer.puts('"done"') output = read_until(reader, '=> "done"') writer.print("exit\n") read_until(reader, "exit") read_until(reader, "\n") read_until(reader, "\n") writer.close exitstatus = wait_or_die(pid) [output, exitstatus] rescue PTY::ChildExited => e [output, e.status] end end end it "boots correctly with -lauto" do output, exitstatus = run_chef_shell_with("-lauto") output.should include("done") expect(exitstatus).to eq(0) end it "sets the log_level from the command line" do output, exitstatus = run_chef_shell_with("-lfatal") do |out, keyboard| show_log_level_code = %q[puts "===#{Chef::Log.level}==="] keyboard.puts(show_log_level_code) read_until(out, show_log_level_code) end output.should include("===fatal===") expect(exitstatus).to eq(0) end end end chef-11.8.2/lib/0000755000004100000410000000000012254362222013306 5ustar www-datawww-datachef-11.8.2/lib/chef/0000755000004100000410000000000012254362222014213 5ustar www-datawww-datachef-11.8.2/lib/chef/mixins.rb0000644000004100000410000000070012254362222016044 0ustar www-datawww-datarequire 'chef/mixin/shell_out' require 'chef/mixin/checksum' require 'chef/mixin/command' require 'chef/mixin/convert_to_class_name' require 'chef/mixin/create_path' require 'chef/mixin/deep_merge' require 'chef/mixin/enforce_ownership_and_permissions' require 'chef/mixin/from_file' require 'chef/mixin/params_validate' require 'chef/mixin/path_sanity' require 'chef/mixin/template' require 'chef/mixin/securable' require 'chef/mixin/xml_escape' chef-11.8.2/lib/chef/mixin/0000755000004100000410000000000012254362222015337 5ustar www-datawww-datachef-11.8.2/lib/chef/mixin/checksum.rb0000644000004100000410000000155412254362222017473 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'digest/sha2' require 'chef/digester' class Chef module Mixin module Checksum def checksum(file) Chef::Digester.checksum_for_file(file) end end end end chef-11.8.2/lib/chef/mixin/language_include_attribute.rb0000644000004100000410000000207512254362222023241 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008, 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/dsl/include_attribute' require 'chef/mixin/deprecation' class Chef module Mixin # DEPRECATED: This is just here for compatibility, use # Chef::DSL::IncludeAttribute instead. deprecate_constant(:LanguageIncludeAttribute, Chef::DSL::IncludeAttribute, <<-EOM) Chef::Mixin::LanguageIncludeAttribute is deprecated. Use Chef::DSL::IncludeAttribute instead. EOM end end chef-11.8.2/lib/chef/mixin/deprecation.rb0000644000004100000410000000674212254362222020172 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef module Mixin def self.deprecated_constants @deprecated_constants ||= {} end # Add a deprecated constant to the Chef::Mixin namespace. # === Arguments # * name: the constant name, as a relative symbol. # * replacement: the constant to return instead. # * message: A message telling the user what to do instead. # === Example: # deprecate_constant(:RecipeDefinitionDSLCore, Chef::DSL::Recipe, <<-EOM) # Chef::Mixin::RecipeDefinitionDSLCore is deprecated, use Chef::DSL::Recipe instead. # EOM def self.deprecate_constant(name, replacement, message) deprecated_constants[name] = {:replacement => replacement, :message => message} end # Const missing hook to look up deprecated constants defined with # deprecate_constant. Emits a warning to the logger and returns the # replacement constant. Will call super, most likely causing an exception # for the missing constant, if +name+ is not found in the # deprecated_constants collection. def self.const_missing(name) if new_const = deprecated_constants[name] Chef::Log.warn(new_const[:message]) Chef::Log.warn("Called from: \n#{caller[0...3].map {|l| "\t#{l}"}.join("\n")}") new_const[:replacement] else super end end module Deprecation class DeprecatedObjectProxyBase KEEPERS = %w{__id__ __send__ instance_eval == equal? initialize object_id} instance_methods.each { |method_name| undef_method(method_name) unless KEEPERS.include?(method_name.to_s)} end class DeprecatedInstanceVariable < DeprecatedObjectProxyBase def initialize(target, ivar_name, level=nil) @target, @ivar_name = target, ivar_name @level ||= :warn end def method_missing(method_name, *args, &block) log_deprecation_msg(caller[0..3]) @target.send(method_name, *args, &block) end def inspect @target.inspect end private def log_deprecation_msg(*called_from) called_from = called_from.flatten log("Accessing #{@ivar_name} by the variable @#{@ivar_name} is deprecated. Support will be removed in a future release.") log("Please update your cookbooks to use #{@ivar_name} in place of @#{@ivar_name}. Accessed from:") called_from.each {|l| log(l)} end def log(msg) # WTF: I don't get the log prefix (i.e., "[timestamp] LEVEL:") if I # send to Chef::Log. No one but me should use method_missing, ever. Chef::Log.logger.send(@level, msg) end end def deprecated_ivar(obj, name, level=nil) DeprecatedInstanceVariable.new(obj, name, level) end end end end chef-11.8.2/lib/chef/mixin/xml_escape.rb0000644000004100000410000001151312254362222020005 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 Opscode, Inc. # Copyright:: Copyright (c) 2005 Sam Ruby # License:: Apache License, Version 2.0 # # 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. #-- # Portions of this code are adapted from Sam Ruby's xchar.rb # http://intertwingly.net/stories/2005/09/28/xchar.rb # # Such code appears here under Sam's original MIT license, while portions of # this file are covered by the above Apache License. For a completely MIT # licensed version, please see Sam's original. # # Thanks, Sam! # # Copyright (c) 2005, Sam Ruby # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. require 'chef/log' begin require 'fast_xs' rescue LoadError Chef::Log.info "The fast_xs gem is not installed, slower pure ruby XML escaping will be used." end class Chef module Mixin module XMLEscape module PureRuby extend self CP1252 = { 128 => 8364, # euro sign 130 => 8218, # single low-9 quotation mark 131 => 402, # latin small letter f with hook 132 => 8222, # double low-9 quotation mark 133 => 8230, # horizontal ellipsis 134 => 8224, # dagger 135 => 8225, # double dagger 136 => 710, # modifier letter circumflex accent 137 => 8240, # per mille sign 138 => 352, # latin capital letter s with caron 139 => 8249, # single left-pointing angle quotation mark 140 => 338, # latin capital ligature oe 142 => 381, # latin capital letter z with caron 145 => 8216, # left single quotation mark 146 => 8217, # right single quotation mark 147 => 8220, # left double quotation mark 148 => 8221, # right double quotation mark 149 => 8226, # bullet 150 => 8211, # en dash 151 => 8212, # em dash 152 => 732, # small tilde 153 => 8482, # trade mark sign 154 => 353, # latin small letter s with caron 155 => 8250, # single right-pointing angle quotation mark 156 => 339, # latin small ligature oe 158 => 382, # latin small letter z with caron 159 => 376 # latin capital letter y with diaeresis } # http://www.w3.org/TR/REC-xml/#dt-chardata PREDEFINED = { 38 => '&', # ampersand 60 => '<', # left angle bracket 62 => '>' # right angle bracket } # http://www.w3.org/TR/REC-xml/#charsets VALID = [[0x9, 0xA, 0xD], (0x20..0xD7FF), (0xE000..0xFFFD), (0x10000..0x10FFFF)] def xml_escape(unescaped_str) begin unescaped_str.unpack("U*").map {|char| xml_escape_char!(char)}.join rescue unescaped_str.unpack("C*").map {|char| xml_escape_char!(char)}.join end end private def xml_escape_char!(char) char = CP1252[char] || char char = 42 unless VALID.detect {|range| range.include? char} char = PREDEFINED[char] || (char<128 ? char.chr : "&##{char};") end end module FastXS extend self def xml_escape(string) string.fast_xs end end if "strings".respond_to?(:fast_xs) include FastXS extend FastXS else include PureRuby extend PureRuby end end end end chef-11.8.2/lib/chef/mixin/shell_out.rb0000644000004100000410000000554112254362222017667 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # chef/shell_out has been deprecated in favor of mixlib/shellout # chef/shell_out is still required here to ensure backward compatibility require 'chef/shell_out' require 'mixlib/shellout' require 'chef/config' class Chef module Mixin module ShellOut # shell_out! runs a command on the system and will raise an error if the command fails, which is what you want # for debugging, shell_out and shell_out! both will display command output to the tty when the log level is debug # Generally speaking, 'extend Chef::Mixin::ShellOut' in your recipes and include 'Chef::Mixin::ShellOut' in your LWRPs # You can also call Mixlib::Shellout.new directly, but you lose all of the above functionality def shell_out(*command_args) cmd = Mixlib::ShellOut.new(*run_command_compatible_options(command_args)) if STDOUT.tty? && !Chef::Config[:daemon] && Chef::Log.debug? cmd.live_stream = STDOUT end cmd.run_command cmd end def shell_out!(*command_args) cmd= shell_out(*command_args) cmd.error! cmd end DEPRECATED_OPTIONS = [ [:command_log_level, :log_level], [:command_log_prepend, :log_tag] ] # CHEF-3090: Deprecate command_log_level and command_log_prepend # Patterned after https://github.com/opscode/chef/commit/e1509990b559984b43e428d4d801c394e970f432 def run_command_compatible_options(command_args) return command_args unless command_args.last.is_a?(Hash) _command_args = command_args.dup _options = _command_args.last DEPRECATED_OPTIONS.each do |old_option, new_option| # Edge case: someone specifies :command_log_level and 'command_log_level' in the option hash next unless value = _options.delete(old_option) || _options.delete(old_option.to_s) deprecate_option old_option, new_option _options[new_option] = value end return _command_args end private def deprecate_option(old_option, new_option) Chef::Log.logger.warn "DEPRECATION: Chef::Mixin::ShellOut option :#{old_option} is deprecated. Use :#{new_option}" end end end end chef-11.8.2/lib/chef/mixin/command.rb0000644000004100000410000001656512254362222017317 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/log' require 'chef/exceptions' require 'tmpdir' require 'fcntl' require 'etc' class Chef module Mixin #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # NOTE: # The popen4 method upon which all the code here is based has a race # condition where it may fail to read all of the data written to stdout and # stderr after the child process exits. The tests for the code here # occasionally fail because of this race condition, so they have been # tagged "volatile". # # This code is considered deprecated, so it should not need to be modified # frequently, if at all. HOWEVER, if you do modify the code here, you must # explicitly enable volatile tests: # # bundle exec rspec spec/unit/mixin/command_spec.rb -t volatile # # In addition, you should make a note that tests need to be run with # volatile tests enabled on any pull request or bug report you submit with # your patch. #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! module Command extend self # NOTE: run_command is deprecated in favor of using Chef::Shellout which now comes from the mixlib-shellout gem. NOTE # if RUBY_PLATFORM =~ /mswin|mingw32|windows/ require 'chef/mixin/command/windows' include ::Chef::Mixin::Command::Windows extend ::Chef::Mixin::Command::Windows else require 'chef/mixin/command/unix' include ::Chef::Mixin::Command::Unix extend ::Chef::Mixin::Command::Unix end # === Parameters # args: A number of required and optional arguments # command, : A complete command with options to execute or a command and options as an Array # creates: The absolute path to a file that prevents the command from running if it exists # cwd: Working directory to execute command in, defaults to Dir.tmpdir # timeout: How many seconds to wait for the command to execute before timing out # returns: The single exit value command is expected to return, otherwise causes an exception # ignore_failure: Whether to raise an exception on failure, or just return the status # output_on_failure: Return output in raised exception regardless of Log.level # # user: The UID or user name of the user to execute the command as # group: The GID or group name of the group to execute the command as # environment: Pairs of environment variable names and their values to set before execution # # === Returns # Returns the exit status of args[:command] def run_command(args={}) status, stdout, stderr = run_command_and_return_stdout_stderr(args) status end # works same as above, except that it returns stdout and stderr # requirement => platforms like solaris 9,10 has wierd issues where # even in command failure the exit code is zero, so we need to lookup stderr. def run_command_and_return_stdout_stderr(args={}) command_output = "" args[:ignore_failure] ||= false args[:output_on_failure] ||= false # TODO: This is the wrong place for this responsibility. if args.has_key?(:creates) if File.exists?(args[:creates]) Chef::Log.debug("Skipping #{args[:command]} - creates #{args[:creates]} exists.") return false end end status, stdout, stderr = output_of_command(args[:command], args) command_output << "STDOUT: #{stdout}" command_output << "STDERR: #{stderr}" handle_command_failures(status, command_output, args) return status, stdout, stderr end def output_of_command(command, args) Chef::Log.debug("Executing #{command}") stderr_string, stdout_string, status = "", "", nil exec_processing_block = lambda do |pid, stdin, stdout, stderr| stdout_string, stderr_string = stdout.string.chomp, stderr.string.chomp end args[:cwd] ||= Dir.tmpdir unless ::File.directory?(args[:cwd]) raise Chef::Exceptions::Exec, "#{args[:cwd]} does not exist or is not a directory" end Dir.chdir(args[:cwd]) do if args[:timeout] begin Timeout.timeout(args[:timeout]) do status = popen4(command, args, &exec_processing_block) end rescue Timeout::Error => e Chef::Log.error("#{command} exceeded timeout #{args[:timeout]}") raise(e) end else status = popen4(command, args, &exec_processing_block) end Chef::Log.debug("---- Begin output of #{command} ----") Chef::Log.debug("STDOUT: #{stdout_string}") Chef::Log.debug("STDERR: #{stderr_string}") Chef::Log.debug("---- End output of #{command} ----") Chef::Log.debug("Ran #{command} returned #{status.exitstatus}") end return status, stdout_string, stderr_string end def handle_command_failures(status, command_output, opts={}) unless opts[:ignore_failure] opts[:returns] ||= 0 unless Array(opts[:returns]).include?(status.exitstatus) # if the log level is not debug, through output of command when we fail output = "" if Chef::Log.level == :debug || opts[:output_on_failure] output << "\n---- Begin output of #{opts[:command]} ----\n" output << command_output.to_s output << "\n---- End output of #{opts[:command]} ----\n" end raise Chef::Exceptions::Exec, "#{opts[:command]} returned #{status.exitstatus}, expected #{opts[:returns]}#{output}" end end end # Call #run_command but set LC_ALL to the system's current environment so it doesn't get changed to C. # # === Parameters # args: A number of required and optional arguments that will be handed out to #run_command # # === Returns # Returns the result of #run_command def run_command_with_systems_locale(args={}) args[:environment] ||= {} args[:environment]["LC_ALL"] = ENV["LC_ALL"] run_command args end # def popen4(cmd, args={}, &b) # @@os_handler.popen4(cmd, args, &b) # end # module_function :popen4 def chdir_or_tmpdir(dir, &block) dir ||= Dir.tmpdir unless File.directory?(dir) raise Chef::Exceptions::Exec, "#{dir} does not exist or is not a directory" end Dir.chdir(dir) do block.call end end end end end chef-11.8.2/lib/chef/mixin/deep_merge.rb0000644000004100000410000001366412254362222017772 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Steve Midgley (http://www.misuse.org/science) # Copyright:: Copyright (c) 2009 Opscode, Inc. # Copyright:: Copyright (c) 2008 Steve Midgley # License:: Apache License, Version 2.0 # # 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. class Chef module Mixin # == Chef::Mixin::DeepMerge # Implements a deep merging algorithm for nested data structures. # ==== Notice: # This code was originally imported from deep_merge by Steve Midgley. # deep_merge is available under the MIT license from # http://trac.misuse.org/science/wiki/DeepMerge module DeepMerge class InvalidSubtractiveMerge < ArgumentError; end OLD_KNOCKOUT_PREFIX = "!merge:".freeze # Regex to match the "knockout prefix" that was used to indicate # subtractive merging in Chef 10.x and previous. Subtractive merging is # removed as of Chef 11, but we detect attempted use of it and raise an # error (see: raise_if_knockout_used!) OLD_KNOCKOUT_MATCH = %r[!merge].freeze extend self def merge(first, second) first = Mash.new(first) unless first.kind_of?(Mash) second = Mash.new(second) unless second.kind_of?(Mash) DeepMerge.deep_merge(second, first) end # Inherited roles use the knockout_prefix array subtraction functionality # This is likely to go away in Chef >= 0.11 def role_merge(first, second) first = Mash.new(first) unless first.kind_of?(Mash) second = Mash.new(second) unless second.kind_of?(Mash) DeepMerge.deep_merge(second, first) end class InvalidParameter < StandardError; end # Deep Merge core documentation. # deep_merge! method permits merging of arbitrary child elements. The two top level # elements must be hashes. These hashes can contain unlimited (to stack limit) levels # of child elements. These child elements to not have to be of the same types. # Where child elements are of the same type, deep_merge will attempt to merge them together. # Where child elements are not of the same type, deep_merge will skip or optionally overwrite # the destination element with the contents of the source element at that level. # So if you have two hashes like this: # source = {:x => [1,2,3], :y => 2} # dest = {:x => [4,5,'6'], :y => [7,8,9]} # dest.deep_merge!(source) # Results: {:x => [1,2,3,4,5,'6'], :y => 2} # By default, "deep_merge!" will overwrite any unmergeables and merge everything else. # To avoid this, use "deep_merge" (no bang/exclamation mark) def deep_merge!(source, dest) # if dest doesn't exist, then simply copy source to it if dest.nil? dest = source; return dest end raise_if_knockout_used!(source) raise_if_knockout_used!(dest) case source when nil dest when Hash source.each do |src_key, src_value| if dest.kind_of?(Hash) if dest[src_key] dest[src_key] = deep_merge!(src_value, dest[src_key]) else # dest[src_key] doesn't exist so we take whatever source has raise_if_knockout_used!(src_value) dest[src_key] = src_value end else # dest isn't a hash, so we overwrite it completely dest = source end end when Array if dest.kind_of?(Array) dest = dest | source else dest = source end when String dest = source else # src_hash is not an array or hash, so we'll have to overwrite dest dest = source end dest end # deep_merge! def hash_only_merge(merge_onto, merge_with) hash_only_merge!(merge_onto.dup, merge_with.dup) end # Deep merge without Array merge. # `merge_onto` is the object that will "lose" in case of conflict. # `merge_with` is the object whose values will replace `merge_onto`s # values when there is a conflict. def hash_only_merge!(merge_onto, merge_with) # If there are two Hashes, recursively merge. if merge_onto.kind_of?(Hash) && merge_with.kind_of?(Hash) merge_with.each do |key, merge_with_value| merge_onto[key] = hash_only_merge!(merge_onto[key], merge_with_value) end merge_onto # If merge_with is nil, don't replace merge_onto elsif merge_with.nil? merge_onto # In all other cases, replace merge_onto with merge_with else merge_with end end # Checks for attempted use of subtractive merge, which was removed for # Chef 11.0. If subtractive merge use is detected, will raise an # InvalidSubtractiveMerge exception. def raise_if_knockout_used!(obj) if uses_knockout?(obj) raise InvalidSubtractiveMerge, "subtractive merge with !merge is no longer supported" end end # Checks for attempted use of subtractive merge in +obj+. def uses_knockout?(obj) case obj when String obj =~ OLD_KNOCKOUT_MATCH when Array obj.any? {|element| element.respond_to?(:gsub) && element =~ OLD_KNOCKOUT_MATCH } else false end end def deep_merge(source, dest) deep_merge!(source.dup, dest.dup) end end end end chef-11.8.2/lib/chef/mixin/command/0000755000004100000410000000000012254362222016755 5ustar www-datawww-datachef-11.8.2/lib/chef/mixin/command/windows.rb0000644000004100000410000000406312254362222020777 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # Author:: Doug MacEachern () # Copyright:: Copyright (c) 2010 VMware, Inc. # License:: Apache License, Version 2.0 # # 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. # if RUBY_VERSION =~ /^1\.8/ require 'win32/open3' else require 'open3' end class Chef module Mixin module Command module Windows def popen4(cmd, args={}, &b) # By default, we are waiting before we yield the block. args[:waitlast] ||= false #XXX :user, :group, :environment support? Open3.popen3(cmd) do |stdin,stdout,stderr,cid| if b if args[:waitlast] b[cid, stdin, stdout, stderr] # send EOF so that if the child process is reading from STDIN # it will actually finish up and exit stdin.close_write else o = StringIO.new e = StringIO.new stdin.close stdout.sync = true stderr.sync = true line = stdout.gets(nil) if line o.write(line) end line = stderr.gets(nil) if line e.write(line) end o.rewind e.rewind b[cid, stdin, o, e] end else [cid, stdin, stdout, stderr] end end $? end end end end end chef-11.8.2/lib/chef/mixin/command/unix.rb0000644000004100000410000001604512254362222020273 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef module Mixin module Command module Unix # This is taken directly from Ara T Howard's Open4 library, and then # modified to suit the needs of Chef. Any bugs here are most likely # my own, and not Ara's. # # The original appears in external/open4.rb in its unmodified form. # # Thanks Ara! def popen4(cmd, args={}, &b) # Ruby 1.8 suffers from intermittent segfaults believed to be due to GC while IO.select # See CHEF-2916 / CHEF-1305 GC.disable # Waitlast - this is magic. # # Do we wait for the child process to die before we yield # to the block, or after? That is the magic of waitlast. # # By default, we are waiting before we yield the block. args[:waitlast] ||= false args[:user] ||= nil unless args[:user].kind_of?(Integer) args[:user] = Etc.getpwnam(args[:user]).uid if args[:user] end args[:group] ||= nil unless args[:group].kind_of?(Integer) args[:group] = Etc.getgrnam(args[:group]).gid if args[:group] end args[:environment] ||= {} # Default on C locale so parsing commands output can be done # independently of the node's default locale. # "LC_ALL" could be set to nil, in which case we also must ignore it. unless args[:environment].has_key?("LC_ALL") args[:environment]["LC_ALL"] = "C" end pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe verbose = $VERBOSE begin $VERBOSE = nil ps.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) cid = fork { pw.last.close STDIN.reopen pw.first pw.first.close pr.first.close STDOUT.reopen pr.last pr.last.close pe.first.close STDERR.reopen pe.last pe.last.close STDOUT.sync = STDERR.sync = true if args[:group] Process.egid = args[:group] Process.gid = args[:group] end if args[:user] Process.euid = args[:user] Process.uid = args[:user] end args[:environment].each do |key,value| ENV[key] = value end if args[:umask] umask = ((args[:umask].respond_to?(:oct) ? args[:umask].oct : args[:umask].to_i) & 007777) File.umask(umask) end begin if cmd.kind_of?(Array) exec(*cmd) else exec(cmd) end raise 'forty-two' rescue Exception => e Marshal.dump(e, ps.last) ps.last.flush end ps.last.close unless (ps.last.closed?) exit! } ensure $VERBOSE = verbose end [pw.first, pr.last, pe.last, ps.last].each{|fd| fd.close} begin e = Marshal.load ps.first raise(Exception === e ? e : "unknown failure!") rescue EOFError # If we get an EOF error, then the exec was successful 42 ensure ps.first.close end pw.last.sync = true pi = [pw.last, pr.first, pe.first] if b begin if args[:waitlast] b[cid, *pi] # send EOF so that if the child process is reading from STDIN # it will actually finish up and exit pi[0].close_write Process.waitpid2(cid).last else # This took some doing. # The trick here is to close STDIN # Then set our end of the childs pipes to be O_NONBLOCK # Then wait for the child to die, which means any IO it # wants to do must be done - it's dead. If it isn't, # it's because something totally skanky is happening, # and we don't care. o = StringIO.new e = StringIO.new pi[0].close stdout = pi[1] stderr = pi[2] stdout.sync = true stderr.sync = true stdout.fcntl(Fcntl::F_SETFL, pi[1].fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK) stderr.fcntl(Fcntl::F_SETFL, pi[2].fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK) stdout_finished = false stderr_finished = false results = nil while !stdout_finished || !stderr_finished begin channels_to_watch = [] channels_to_watch << stdout if !stdout_finished channels_to_watch << stderr if !stderr_finished ready = IO.select(channels_to_watch, nil, nil, 1.0) rescue Errno::EAGAIN ensure results = Process.waitpid2(cid, Process::WNOHANG) if results stdout_finished = true stderr_finished = true end end if ready && ready.first.include?(stdout) line = results ? stdout.gets(nil) : stdout.gets if line o.write(line) else stdout_finished = true end end if ready && ready.first.include?(stderr) line = results ? stderr.gets(nil) : stderr.gets if line e.write(line) else stderr_finished = true end end end results = Process.waitpid2(cid) unless results o.rewind e.rewind b[cid, pi[0], o, e] results.last end ensure pi.each{|fd| fd.close unless fd.closed?} end else [cid, pw.last, pr.first, pe.first] end ensure GC.enable end end end end end chef-11.8.2/lib/chef/mixin/get_source_from_package.rb0000644000004100000410000000306112254362222022521 0ustar www-datawww-data# Author:: Lamont Granquist () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # # # mixin to make this syntax work without specifying a source: # # gem_pacakge "/tmp/foo-x.y.z.gem" # rpm_package "/tmp/foo-x.y-z.rpm" # dpkg_package "/tmp/foo-x.y.z.deb" # class Chef module Mixin module GetSourceFromPackage def initialize(new_resource, run_context) super # if we're passed something that looks like a filesystem path, with no source, use it # - require at least one '/' in the path to avoid gem_package "foo" breaking if a file named 'foo' exists in the cwd if new_resource.source.nil? && new_resource.package_name.match(/#{::File::SEPARATOR}/) && ::File.exists?(new_resource.package_name) Chef::Log.debug("No package source specified, but #{new_resource.package_name} exists on the filesystem, copying to package source") new_resource.source(@new_resource.package_name) end end end end end chef-11.8.2/lib/chef/mixin/recipe_definition_dsl_core.rb0000644000004100000410000000224012254362222023213 0ustar www-datawww-data#-- # Author:: Adam Jacob () # Author:: Christopher Walters () # Copyright:: Copyright (c) 2008, 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # ### # NOTE: This file and constant are here only for backwards compatibility. # New code should use Chef::DSL::Recipe instead. # # This constant (module name) will eventually be deprecated and then removed. ### require 'chef/mixin/deprecation' class Chef module Mixin deprecate_constant(:RecipeDefinitionDSLCore, Chef::DSL::Recipe, <<-EOM) Chef::Mixin::RecipeDefinitionDSLCore is deprecated. Use Chef::DSL::Recipe instead. EOM end end chef-11.8.2/lib/chef/mixin/securable.rb0000644000004100000410000001672412254362222017643 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef module Mixin module Securable def owner(arg=nil) set_or_return( :owner, arg, :regex => Chef::Config[:user_valid_regex] ) end alias :user :owner def group(arg=nil) set_or_return( :group, arg, :regex => Chef::Config[:group_valid_regex] ) end def mode(arg=nil) set_or_return( :mode, arg, :callbacks => { "not in valid numeric range" => lambda { |m| if m.kind_of?(String) m =~ /^0/ || m="0#{m}" end # Windows does not support the sticky or setuid bits if Chef::Platform.windows? Integer(m)<=0777 && Integer(m)>=0 else Integer(m)<=07777 && Integer(m)>=0 end }, } ) end #==WindowsMacros # Defines methods for adding attributes to a chef resource to describe # Windows file security metadata. # # This module is meant to be used to extend a class (instead of # `include`-ing). A class is automatically extended with this module when # it includes WindowsSecurableAttributes. # -- # TODO should this be separated into different files? module WindowsMacros # === rights_attribute # "meta-method" for dynamically creating rights attributes on resources. # # Multiple rights attributes can be declared. This enables resources to # have multiple rights attributes with separate runtime states. # # For example, +Chef::Resource::RemoteDirectory+ supports different # rights on the directories and files by declaring separate rights # attributes for each (rights and files_rights). # # ==== User Level API # Given a resource that calls # # rights_attribute(:rights) # # Then the resource DSL could be used like this: # # rights :read, ["Administrators","Everyone"] # rights :deny, "Pinky" # rights :full_control, "Users", :applies_to_children => true # rights :write, "John Keiser", :applies_to_children => :containers_only, :applies_to_self => false, :one_level_deep => true # # ==== Internal Data Structure # rights attributes support multiple right declarations # in a single resource block--the data will be merged # into a single internal hash. # # The internal representation is a hash with the following keys: # # * `:permissions`: Integer of Windows permissions flags, 1..2^32 # or one of `[:full_control, :modify, :read_execute, :read, :write]` # * `:principals`: String or Array of Strings represnting usernames on # the system. # * `:applies_to_children` (optional): Boolean # * `:applies_to_self` (optional): Boolean # * `:one_level_deep` (optional): Boolean # def rights_attribute(name) # equivalent to something like: # def rights(permissions=nil, principals=nil, args_hash=nil) define_method(name) do |*args| # Ruby 1.8 compat: default the arguments permissions = args.length >= 1 ? args[0] : nil principals = args.length >= 2 ? args[1] : nil args_hash = args.length >= 3 ? args[2] : nil raise ArgumentError.new("wrong number of arguments (#{args.length} for 3)") if args.length >= 4 rights = self.instance_variable_get("@#{name.to_s}".to_sym) unless permissions.nil? input = { :permissions => permissions, :principals => principals } input.merge!(args_hash) unless args_hash.nil? validations = {:permissions => { :required => true }, :principals => { :required => true, :kind_of => [String, Array] }, :applies_to_children => { :equal_to => [ true, false, :containers_only, :objects_only ]}, :applies_to_self => { :kind_of => [ TrueClass, FalseClass ] }, :one_level_deep => { :kind_of => [ TrueClass, FalseClass ] } } validate(input, validations) [ permissions ].flatten.each do |permission| if permission.is_a?(Integer) if permission < 0 || permission > 1<<32 raise ArgumentError, "permissions flags must be positive and <= 32 bits (#{permission})" end elsif !([:full_control, :modify, :read_execute, :read, :write].include?(permission.to_sym)) raise ArgumentError, "permissions parameter must be :full_control, :modify, :read_execute, :read, :write or an integer representing Windows permission flags" end end [ principals ].flatten.each do |principal| if !principal.is_a?(String) raise ArgumentError, "principals parameter must be a string or array of strings representing usernames" end end if input[:applies_to_children] == false if input[:applies_to_self] == false raise ArgumentError, "'rights' attribute must specify either :applies_to_children or :applies_to_self." end if input[:one_level_deep] == true raise ArgumentError, "'rights' attribute specified :one_level_deep without specifying :applies_to_children." end end rights ||= [] rights << input end set_or_return( name, rights, {} ) end end end #==WindowsSecurableAttributes # Defines #inherits to describe Windows file security ACLs on the # including class module WindowsSecurableAttributes def inherits(arg=nil) set_or_return( :inherits, arg, :kind_of => [ TrueClass, FalseClass ] ) end end if RUBY_PLATFORM =~ /mswin|mingw|windows/ include WindowsSecurableAttributes end # Callback that fires when included; will extend the including class # with WindowsMacros and define #rights and #deny_rights on it. def self.included(including_class) if RUBY_PLATFORM =~ /mswin|mingw|windows/ including_class.extend(WindowsMacros) # create a default 'rights' attribute including_class.rights_attribute(:rights) including_class.rights_attribute(:deny_rights) end end end end end chef-11.8.2/lib/chef/mixin/convert_to_class_name.rb0000644000004100000410000000342312254362222022235 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Walters () # Copyright:: Copyright (c) 2008, 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef module Mixin module ConvertToClassName extend self def convert_to_class_name(str) str = str.dup str.gsub!(/[^A-Za-z0-9_]/,'_') rname = nil regexp = %r{^(.+?)(_(.+))?$} mn = str.match(regexp) if mn rname = mn[1].capitalize while mn && mn[3] mn = mn[3].match(regexp) rname << mn[1].capitalize if mn end end rname end def convert_to_snake_case(str, namespace=nil) str = str.dup str.sub!(/^#{namespace}(\:\:)?/, '') if namespace str.gsub!(/[A-Z]/) {|s| "_" + s} str.downcase! str.sub!(/^\_/, "") str end def snake_case_basename(str) with_namespace = convert_to_snake_case(str) with_namespace.split("::").last.sub(/^_/, '') end def filename_to_qualified_string(base, filename) file_base = File.basename(filename, ".rb") base.to_s + (file_base == 'default' ? '' : "_#{file_base}") end end end end chef-11.8.2/lib/chef/mixin/path_sanity.rb0000644000004100000410000000377512254362222020223 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef module Mixin module PathSanity def enforce_path_sanity(env=ENV) if Chef::Config[:enforce_path_sanity] path_separator = Chef::Platform.windows? ? ';' : ':' existing_paths = env["PATH"].split(path_separator) # ensure the Ruby and Gem bindirs are included # mainly for 'full-stack' Chef installs paths_to_add = [] paths_to_add << ruby_bindir unless sane_paths.include?(ruby_bindir) paths_to_add << gem_bindir unless sane_paths.include?(gem_bindir) paths_to_add << sane_paths if sane_paths paths_to_add.flatten!.compact! paths_to_add.each do |sane_path| unless existing_paths.include?(sane_path) env_path = env["PATH"].dup env_path << path_separator unless env["PATH"].empty? env_path << sane_path env["PATH"] = env_path end end end end private def sane_paths @sane_paths ||= begin if Chef::Platform.windows? %w[] else %w[/usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin] end end end def ruby_bindir RbConfig::CONFIG['bindir'] end def gem_bindir Gem.bindir end end end end chef-11.8.2/lib/chef/mixin/params_validate.rb0000644000004100000410000002130512254362222021021 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. class Chef class DelayedEvaluator < Proc end module Mixin module ParamsValidate # 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 lazy(&block) DelayedEvaluator.new(&block) end def set_or_return(symbol, arg, validation) iv_symbol = "@#{symbol.to_s}".to_sym if arg == nil && self.instance_variable_defined?(iv_symbol) == true ivar = self.instance_variable_get(iv_symbol) if(ivar.is_a?(DelayedEvaluator)) validate({ symbol => ivar.call }, { symbol => validation })[symbol] else ivar end else if(arg.is_a?(DelayedEvaluator)) val = arg else val = validate({ symbol => arg }, { symbol => validation })[symbol] end self.instance_variable_set(iv_symbol, val) 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 Exceptions::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 Exceptions::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 Exceptions::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 Exceptions::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 Exceptions::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 Exceptions::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 Exceptions::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 Exceptions::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 end chef-11.8.2/lib/chef/mixin/from_file.rb0000644000004100000410000000322612254362222017631 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Walters () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef module Mixin module FromFile # Loads a given ruby file, and runs instance_eval against it in the context of the current # object. # # Raises an IOError if the file cannot be found, or is not readable. def from_file(filename) if File.exists?(filename) && File.readable?(filename) self.instance_eval(IO.read(filename), filename, 1) else raise IOError, "Cannot open or read #{filename}!" end end # Loads a given ruby file, and runs class_eval against it in the context of the current # object. # # Raises an IOError if the file cannot be found, or is not readable. def class_from_file(filename) if File.exists?(filename) && File.readable?(filename) self.class_eval(IO.read(filename), filename, 1) else raise IOError, "Cannot open or read #{filename}!" end end end end end chef-11.8.2/lib/chef/mixin/create_path.rb0000644000004100000410000000370412254362222020147 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. class Chef module Mixin module CreatePath # Creates a given path, including all directories that lead up to it. # Like mkdir_p, but without the leaking. # # === Parameters # file_path:: A string that represents the path to create, # or an Array with the path-parts. # # === Returns # The created file_path. def create_path(file_path) unless file_path.kind_of?(String) || file_path.kind_of?(Array) raise ArgumentError, "file_path must be a string or an array!" end if file_path.kind_of?(String) file_path = File.expand_path(file_path).split(File::SEPARATOR) file_path.shift if file_path[0] == '' # Check if path starts with a separator or drive letter (Windows) unless file_path[0].match("^#{File::SEPARATOR}|^[a-zA-Z]:") file_path[0] = "#{File::SEPARATOR}#{file_path[0]}" end end file_path.each_index do |i| create_path = File.join(file_path[0, i + 1]) unless File.directory?(create_path) Chef::Log.debug("Creating directory #{create_path}") Dir.mkdir(create_path) end end File.expand_path(File.join(file_path)) end end end end chef-11.8.2/lib/chef/mixin/windows_architecture_helper.rb0000644000004100000410000000607112254362222023463 0ustar www-datawww-data# # Author:: Adam Edwards () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/exceptions' require 'win32/api' if Chef::Platform.windows? class Chef module Mixin module WindowsArchitectureHelper def node_windows_architecture(node) node[:kernel][:machine].to_sym end def wow64_architecture_override_required?(node, desired_architecture) is_i386_windows_process? && node_windows_architecture(node) == :x86_64 && desired_architecture == :x86_64 end def node_supports_windows_architecture?(node, desired_architecture) assert_valid_windows_architecture!(desired_architecture) return (node_windows_architecture(node) == :x86_64 || desired_architecture == :i386) ? true : false end def valid_windows_architecture?(architecture) return (architecture == :x86_64) || (architecture == :i386) end def assert_valid_windows_architecture!(architecture) if ! valid_windows_architecture?(architecture) raise Chef::Exceptions::Win32ArchitectureIncorrect, "The specified architecture was not valid. It must be one of :i386 or :x86_64" end end def is_i386_windows_process? Chef::Platform.windows? && 'X86'.casecmp(ENV['PROCESSOR_ARCHITECTURE']) == 0 end def disable_wow64_file_redirection( node ) original_redirection_state = ['0'].pack('P') if ( ( node_windows_architecture(node) == :x86_64) && ::Chef::Platform.windows?) win32_wow_64_disable_wow_64_fs_redirection = ::Win32::API.new('Wow64DisableWow64FsRedirection', 'P', 'L', 'kernel32') succeeded = win32_wow_64_disable_wow_64_fs_redirection.call(original_redirection_state) if succeeded == 0 raise Win32APIError "Failed to disable Wow64 file redirection" end end original_redirection_state end def restore_wow64_file_redirection( node, original_redirection_state ) if ( (node_windows_architecture(node) == :x86_64) && ::Chef::Platform.windows?) win32_wow_64_revert_wow_64_fs_redirection = ::Win32::API.new('Wow64RevertWow64FsRedirection', 'P', 'L', 'kernel32') succeeded = win32_wow_64_revert_wow_64_fs_redirection.call(original_redirection_state) if succeeded == 0 raise Win32APIError "Failed to revert Wow64 file redirection" end end end end end end chef-11.8.2/lib/chef/mixin/language_include_recipe.rb0000644000004100000410000000170712254362222022506 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008, 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/dsl/include_recipe' require 'chef/mixin/deprecation' class Chef module Mixin deprecate_constant(:LanguageIncludeRecipe, Chef::DSL::IncludeRecipe, <<-EOM) Chef::Mixin::LanguageIncludeRecipe is deprecated, use Chef::DSL::IncludeRecipe instead. EOM end end chef-11.8.2/lib/chef/mixin/file_class.rb0000644000004100000410000000203212254362222017765 0ustar www-datawww-data# # Author:: Mark Mzyk # Author:: Seth Chisamore # Author:: Bryan McLellan # Copyright:: Copyright (c) 2011-2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef module Mixin module FileClass def file_class @host_os_file ||= if Chef::Platform.windows? require 'chef/win32/file' Chef::ReservedNames::Win32::File else ::File end end end end end chef-11.8.2/lib/chef/mixin/language.rb0000644000004100000410000000326712254362222017457 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/dsl/platform_introspection' require 'chef/dsl/data_query' require 'chef/mixin/deprecation' class Chef module Mixin # == [DEPRECATED] Chef::Mixin::DeprecatedLanguageModule # This module is a temporary replacement for the previous # Chef::Mixin::Language. That module's functionality was split into two # modules, Chef::DSL::PlatformIntrospection, and Chef::DSL::DataQuery. # # This module includes both PlatformIntrospection and DataQuery to provide # the same interfaces and behavior as the prior Mixin::Language. # # This module is loaded via const_missing hook when Chef::Mixin::Language # is accessed. See chef/mixin/deprecation for details. module DeprecatedLanguageModule include Chef::DSL::PlatformIntrospection include Chef::DSL::DataQuery end deprecate_constant(:Language, DeprecatedLanguageModule, <<-EOM) Chef::Mixin::Language is deprecated. Use either (or both) Chef::DSL::PlatformIntrospection or Chef::DSL::DataQuery instead. EOM end end chef-11.8.2/lib/chef/mixin/template.rb0000644000004100000410000002055012254362222017501 0ustar www-datawww-data#-- # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'tempfile' require 'erubis' class Chef module Mixin module Template # A compatibility wrapper around IO.binread so it works on Ruby 1.8.7. # -- # Used in the TemplateContext class, but that method namespace is shared # with user code, so we want to avoid adding methods there when possible. def self.binread(file) if IO.respond_to?(:binread) IO.binread(file) else File.open(file, "rb") {|f| f.read } end end # == ChefContext # ChefContext was previously used to mix behavior into Erubis::Context so # that it would be available to templates. This behavior has now moved to # TemplateContext, but this module is still mixed in to the # TemplateContext class so that any user code that modified ChefContext # will continue to work correctly. module ChefContext end # == TemplateContext # TemplateContext is the base context class for all templates in Chef. It # defines user-facing extensions to the base Erubis::Context to provide # enhanced features. Individual instances of TemplateContext can be # extended to add logic to a specific template. # class TemplateContext < Erubis::Context include ChefContext attr_reader :_extension_modules def initialize(variables) super @_extension_modules = [] end ### # USER FACING API ### # Returns the current node object, or raises an error if it's not set. # Provides API consistency, allowing users to reference the node object # by the bare `node` everywhere. def node return @node if @node raise "Could not find a value for node. If you are explicitly setting variables in a template, " + "include a node variable if you plan to use it." end # # Takes the name of the partial, plus a hash of options. Returns a # string that contains the result of the evaluation of the partial. # # All variables from the parent template will be propagated down to # the partial, unless you pass the +variables+ option (see below). # # Valid options are: # # :local:: If true then the partial name will be interpreted as the # path to a file on the local filesystem; if false (the # default) it will be looked up in the cookbook according to # the normal rules for templates. # :source:: If specified then the partial will be looked up with this # name or path (according to the +local+ option) instead of # +partial_name+. # :cookbook:: Search for the partial in the provided cookbook instead # of the cookbook that contains the top-level template. # :variables:: A Hash of variable_name => value that will be made # available to the partial. If specified, none of the # variables from the master template will be, so if you # need them you will need to propagate them explicitly. # def render(partial_name, options = {}) raise "You cannot render partials in this context" unless @template_finder partial_variables = options.delete(:variables) || _public_instance_variables partial_context = self.class.new(partial_variables) partial_context._extend_modules(@_extension_modules) template_location = @template_finder.find(partial_name, options) _render_template(Mixin::Template.binread(template_location), partial_context) end def render_template(template_location) _render_template(Mixin::Template.binread(template_location), self) end def render_template_from_string(template) _render_template(template, self) end ### # INTERNAL PUBLIC API ### def _render_template(template, context) begin eruby = Erubis::Eruby.new(template) output = eruby.evaluate(context) rescue Object => e raise TemplateError.new(e, template, context) end # CHEF-4399 # Erubis always emits unix line endings during template # rendering. Chef used to convert line endings to the # original line endings in the template. However this # created problems in cases when cookbook developer is # coding the cookbook on windows but using it on non-windows # platforms. # The safest solution is to make sure that native to the # platform we are running on is used in order to minimize # potential issues for the applications that will consume # this template. if Chef::Platform.windows? output = output.gsub(/\r?\n/,"\r\n") end output end def _extend_modules(module_names) module_names.each do |mod| context_methods = [:node, :render, :render_template, :render_template_from_string] context_methods.each do |core_method| if mod.method_defined?(core_method) or mod.private_method_defined?(core_method) Chef::Log.warn("Core template method `#{core_method}' overridden by extension module #{mod}") end end extend(mod) @_extension_modules << mod end end # Collects instance variables set on the current object as a Hash # suitable for creating a new TemplateContext. Instance variables that # are only valid for this specific instance are omitted from the # collection. def _public_instance_variables all_ivars = instance_variables all_ivars.delete(:@_extension_modules) all_ivars.inject({}) do |ivar_map, ivar_symbol_name| value = instance_variable_get(ivar_symbol_name) name_without_at = ivar_symbol_name.to_s[1..-1].to_sym ivar_map[name_without_at] = value ivar_map end end end class TemplateError < RuntimeError attr_reader :original_exception, :context SOURCE_CONTEXT_WINDOW = 2 def initialize(original_exception, template, context) @original_exception, @template, @context = original_exception, template, context end def message @original_exception.message end def line_number @line_number ||= $1.to_i if original_exception.backtrace.find {|line| line =~ /\(erubis\):(\d+)/ } end def source_location "on line ##{line_number}" end def source_listing @source_listing ||= begin lines = @template.split(/\n/) if line_number line_index = line_number - 1 beginning_line = line_index <= SOURCE_CONTEXT_WINDOW ? 0 : line_index - SOURCE_CONTEXT_WINDOW source_size = SOURCE_CONTEXT_WINDOW * 2 + 1 else beginning_line = 0 source_size = lines.length end contextual_lines = lines[beginning_line, source_size] output = [] contextual_lines.each_with_index do |line, index| line_number = (index+beginning_line+1).to_s.rjust(3) output << "#{line_number}: #{line}" end output.join("\n") end end def to_s "\n\n#{self.class} (#{message}) #{source_location}:\n\n" + "#{source_listing}\n\n #{original_exception.backtrace.join("\n ")}\n\n" end end end end end chef-11.8.2/lib/chef/mixin/why_run.rb0000644000004100000410000003414212254362222017363 0ustar www-datawww-data# # Author:: Dan DeLeo ( ) # Author:: Marc Paradise ( ) # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef module Mixin module WhyRun # ==ConvergeActions # ConvergeActions implements the logic for why run. A ConvergeActions # object wraps a collection of actions, which consist of a descriptive # string and a block/Proc. Actions are executed by calling #converge! # When why_run mode is enabled, each action's description will be # printed, but the block will not be called. Conversely, in normal mode, # the block is called, but the message is not printed. # # In general, this class should be accessed through the API provided by # Chef::Provider. class ConvergeActions attr_reader :actions def initialize(resource, run_context, action) @resource, @run_context = resource, run_context @actions = [] end def events @run_context.events end # Adds an action to the list. +descriptions+ can either be an Array of # Strings, or a single String describing the action; +block+ is a # block/proc that implements the action. def add_action(descriptions, &block) @actions << [descriptions, block] if !Chef::Config[:why_run] block.call end events.resource_update_applied(@resource, @action, descriptions) end # True if there are no actions to execute. def empty? @actions.empty? end end # == ResourceRequirements # ResourceRequirements provides a framework for making assertions about # the host system's state. It also provides a mechanism for making # assumptions about what the system's state might have been when running # in why run mode. # # For example, consider a recipe that consists of a package resource and # a service resource. If the service's init script is installed by the # package, and Chef is running in why run mode, then the service resource # would fail when attempting to run `/etc/init.d/software-name status`. # In order to provide a more useful approximation of what would happen in # a real chef run, we want to instead assume that the service was created # but isn't running. The logic would look like this: # # # Hypothetical service provider demonstrating why run assumption logic. # # This isn't the actual API, it just shows the logic. # class HypotheticalServiceProvider < Chef::Provider # # def load_current_resource # # Make sure we have the init script available: # if ::File.exist?("/etc/init.d/some-service" # # If the init script exists, proceed as normal: # status_cmd = shell_out("/etc/init.d/some-service status") # if status_cmd.success? # @current_resource.status(:running) # else # @current_resource.status(:stopped) # end # else # if whyrun_mode? # # If the init script is not available, and we're in why run mode, # # assume that some previous action would've created it: # log("warning: init script '/etc/init.d/some-service' is not available") # log("warning: assuming that the init script would have been created, assuming the state of 'some-service' is 'stopped'") # @current_resource.status(:stopped) # else # raise "expected init script /etc/init.d/some-service doesn't exist" # end # end # end # # end # # In short, the code above does the following: # * runs a test to determine if a requirement is met: # `::File.exist?("/etc/init.d/some-service"` # * raises an error if the requirement is not met, and we're not in why # run mode. # * if we *are* in why run mode, print a message explaining the # situation, and run some code that makes an assumption about what the # state of the system would be. In this case, we also skip the normal # `load_current_resource` logic # * when the requirement *is* met, we run the normal `load_current_resource` # logic # # ResourceRequirements encapsulates the above logic in a more declarative API. # # === Examples # Assertions and assumptions should be created through the WhyRun#assert # method, which gets mixed in to providers. See that method's # documentation for examples. class ResourceRequirements # Implements the logic for a single assertion/assumption. See the # documentation for ResourceRequirements for full discussion. class Assertion class AssertionFailure < RuntimeError end def initialize @block_action = false @assertion_proc = nil @failure_message = nil @whyrun_message = nil @resource_modifier = nil @assertion_failed = false @exception_type = AssertionFailure end # Defines the code block that determines if a requirement is met. The # block should return a truthy value to indicate that the requirement # is met, and a falsey value if the requirement is not met. # # in a provider: # assert(:some_action) do |a| # # This provider requires the file /tmp/foo to exist: # a.assertion { ::File.exist?("/tmp/foo") } # end def assertion(&assertion_proc) @assertion_proc = assertion_proc end # Defines the failure message, and optionally the Exception class to # use when a requirement is not met. It works like `raise`: # # in a provider: # assert(:some_action) do |a| # # This example shows usage with 1 or 2 args by calling #failure_message twice. # # In practice you should only call this once per Assertion. # # # Set the Exception class explicitly # a.failure_message(Chef::Exceptions::MissingRequiredFile, "File /tmp/foo doesn't exist") # # Fallback to the default error class (AssertionFailure) # a.failure_message("File /tmp/foo" doesn't exist") # end def failure_message(*args) case args.size when 1 @failure_message = args[0] when 2 @exception_type, @failure_message = args[0], args[1] else raise ArgumentError, "#{self.class}#failure_message takes 1 or 2 arguments, you gave #{args.inspect}" end end # Defines a message and optionally provides a code block to execute # when the requirement is not met and Chef is executing in why run # mode # # If no failure_message is provided (above), then execution # will be allowed to continue in both whyrun and non-whyrun # mode # # With a service resource that requires /etc/init.d/service-name to exist: # # in a provider # assert(:start, :restart) do |a| # a.assertion { ::File.exist?("/etc/init.d/service-name") } # a.whyrun("Init script '/etc/init.d/service-name' doesn't exist, assuming a prior action would have created it.") do # # blindly assume that the service exists but is stopped in why run mode: # @new_resource.status(:stopped) # end # end def whyrun(message, &resource_modifier) @whyrun_message = message @resource_modifier = resource_modifier end # Prevents associated actions from being invoked in whyrun mode. # This will also stop further processing of assertions for a given action. # # An example from the template provider: if the source template doesn't exist # we can't parse it in the action_create block of template - something that we do # even in whyrun mode. Because the source template may have been created in an earlier # step, we still want to keep going in whyrun mode. # # assert(:create, :create_if_missing) do |a| # a.assertion { File::exists?(@new_resource.source) } # a.whyrun "Template source file does not exist, assuming it would have been created." # a.block_action! # end # def block_action! @block_action = true end def block_action? @block_action end def assertion_failed? @assertion_failed end # Runs the assertion/assumption logic. Will raise an Exception of the # type specified in #failure_message (or AssertionFailure by default) # if the requirement is not met and Chef is not running in why run # mode. An exception will also be raised if running in why run mode # and no why run message or block has been declared. def run(action, events, resource) if !@assertion_proc || !@assertion_proc.call @assertion_failed = true if Chef::Config[:why_run] && @whyrun_message events.provider_requirement_failed(action, resource, @exception_type, @failure_message) events.whyrun_assumption(action, resource, @whyrun_message) if @whyrun_message @resource_modifier.call if @resource_modifier else if @failure_message events.provider_requirement_failed(action, resource, @exception_type, @failure_message) raise @exception_type, @failure_message end end end end end def initialize(resource, run_context) @resource, @run_context = resource, run_context @assertions = Hash.new {|h,k| h[k] = [] } @blocked_actions = [] end def events @run_context.events end # Check to see if a given action is blocked by a failed assertion # # Takes the action name to be verified. def action_blocked?(action) @blocked_actions.include?(action) end # Define a new Assertion. # # Takes a list of action names for which the assertion should be made. # ==== Examples: # A File provider that requires the parent directory to exist: # # assert(:create, :create_if_missing) do |a| # parent_dir = File.basename(@new_resource.path) # a.assertion { ::File.directory?(parent_dir) } # a.failure_message(Exceptions::ParentDirectoryDoesNotExist, # "Can't create file #{@new_resource.path}: parent directory #{parent_dir} doesn't exist") # a.why_run("assuming parent directory #{parent_dir} would have been previously created" # end # # A service provider that requires the init script to exist: # # assert(:start, :restart) do |a| # a.assertion { ::File.exist?(@new_resource.init_script) } # a.failure_message(Exceptions::MissingInitScript, # "Can't check status of #{@new_resource}: init script #{@new_resource.init_script} is missing") # a.why_run("Assuming init script would have been created and service is stopped") do # @current_resource.status(:stopped) # end # end # # A File provider that will error out if you don't have permissions do # delete the file, *even in why run mode*: # # assert(:delete) do |a| # a.assertion { ::File.writable?(@new_resource.path) } # a.failure_message(Exceptions::InsufficientPrivileges, # "You don't have sufficient privileges to delete #{@new_resource.path}") # end # # A Template provider that will prevent action execution but continue the run in # whyrun mode if the template source is not available. # assert(:create, :create_if_missing) do |a| # a.assertion { File::exist?(@new_resource.source) } # a.failure_message Chef::Exceptions::TemplateError, "Template #{@new_resource.source} could not be found exist." # a.whyrun "Template source #{@new_resource.source} does not exist. Assuming it would have been created." # a.block_action! # end # # assert(:delete) do |a| # a.assertion { ::File.writable?(@new_resource.path) } # a.failure_message(Exceptions::InsufficientPrivileges, # "You don't have sufficient privileges to delete #{@new_resource.path}") # end def assert(*actions) assertion = Assertion.new yield assertion actions.each {|action| @assertions[action] << assertion } end # Run the assertion and assumption logic. def run(action) @assertions[action.to_sym].each do |a| a.run(action, events, @resource) if a.assertion_failed? and a.block_action? @blocked_actions << action return end end end end end end end chef-11.8.2/lib/chef/mixin/enforce_ownership_and_permissions.rb0000644000004100000410000000233312254362222024661 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/file_access_control' class Chef module Mixin module EnforceOwnershipAndPermissions def access_controls @access_controls ||= Chef::FileAccessControl.new(current_resource, new_resource, self) end # will set the proper user, group and # permissions using a platform specific # version of Chef::FileAccessControl def enforce_ownership_and_permissions access_controls.set_all new_resource.updated_by_last_action(true) if access_controls.modified? end end end end chef-11.8.2/lib/chef/application.rb0000644000004100000410000001773612254362222017061 0ustar www-datawww-data# # Author:: AJ Christensen () # Author:: Mark Mzyk (mmzyk@opscode.com) # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'pp' require 'socket' require 'chef/config' require 'chef/exceptions' require 'chef/log' require 'chef/platform' require 'mixlib/cli' require 'tmpdir' require 'rbconfig' class Chef::Application include Mixlib::CLI def initialize super @chef_client = nil @chef_client_json = nil trap("INT") do Chef::Application.fatal!("SIGINT received, stopping", 2) end unless Chef::Platform.windows? trap("QUIT") do Chef::Log.info("SIGQUIT received, call stack:\n " + caller.join("\n ")) end trap("HUP") do Chef::Log.info("SIGHUP received, reconfiguring") reconfigure end end # Always switch to a readable directory. Keeps subsequent Dir.chdir() {} # from failing due to permissions when launched as a less privileged user. end # Reconfigure the application. You'll want to override and super this method. def reconfigure configure_chef configure_logging end # Get this party started def run reconfigure setup_application run_application end # Parse configuration (options and config file) def configure_chef parse_options load_config_file end # Parse the config file def load_config_file config_fetcher = Chef::ConfigFetcher.new(config[:config_file], Chef::Config.config_file_jail) if config[:config_file].nil? Chef::Log.warn("No config file found or specified on command line, using command line options.") elsif config_fetcher.config_missing? Chef::Log.warn("*****************************************") Chef::Log.warn("Did not find config file: #{config[:config_file]}, using command line options.") Chef::Log.warn("*****************************************") else config_content = config_fetcher.read_config apply_config(config_content, config[:config_file]) end Chef::Config.merge!(config) end # Initialize and configure the logger. # === Loggers and Formatters # In Chef 10.x and previous, the Logger was the primary/only way that Chef # communicated information to the user. In Chef 10.14, a new system, "output # formatters" was added, and in Chef 11.0+ it is the default when running # chef in a console (detected by `STDOUT.tty?`). Because output formatters # are more complex than the logger system and users have less experience with # them, the config option `force_logger` is provided to restore the Chef 10.x # behavior. # # Conversely, for users who want formatter output even when chef is running # unattended, the `force_formatter` option is provided. # # === Auto Log Level # When `log_level` is set to `:auto` (default), the log level will be `:warn` # when the primary output mode is an output formatter (see # +using_output_formatter?+) and `:info` otherwise. # # === Automatic STDOUT Logging # When `force_logger` is configured (e.g., Chef 10 mode), a second logger # with output on STDOUT is added when running in a console (STDOUT is a tty) # and the configured log_location isn't STDOUT. This accounts for the case # that a user has configured a log_location in client.rb, but is running # chef-client by hand to troubleshoot a problem. def configure_logging Chef::Log.init(MonoLogger.new(Chef::Config[:log_location])) if want_additional_logger? configure_stdout_logger end Chef::Log.level = resolve_log_level end def configure_stdout_logger stdout_logger = MonoLogger.new(STDOUT) STDOUT.sync = true stdout_logger.formatter = Chef::Log.logger.formatter Chef::Log.loggers << stdout_logger end # Based on config and whether or not STDOUT is a tty, should we setup a # secondary logger for stdout? def want_additional_logger? ( Chef::Config[:log_location] != STDOUT ) && STDOUT.tty? && (!Chef::Config[:daemonize]) && (Chef::Config[:force_logger]) end # Use of output formatters is assumed if `force_formatter` is set or if # `force_logger` is not set and STDOUT is to a console (tty) def using_output_formatter? Chef::Config[:force_formatter] || (!Chef::Config[:force_logger] && STDOUT.tty?) end def auto_log_level? Chef::Config[:log_level] == :auto end # if log_level is `:auto`, convert it to :warn (when using output formatter) # or :info (no output formatter). See also +using_output_formatter?+ def resolve_log_level if auto_log_level? if using_output_formatter? :warn else :info end else Chef::Config[:log_level] end end # Called prior to starting the application, by the run method def setup_application raise Chef::Exceptions::Application, "#{self.to_s}: you must override setup_application" end # Actually run the application def run_application raise Chef::Exceptions::Application, "#{self.to_s}: you must override run_application" end def self.setup_server_connectivity if Chef::Config.chef_zero.enabled destroy_server_connectivity require 'chef_zero/server' require 'chef/chef_fs/chef_fs_data_store' require 'chef/chef_fs/config' chef_fs = Chef::ChefFS::Config.new.local_fs chef_fs.write_pretty_json = true server_options = {} server_options[:data_store] = Chef::ChefFS::ChefFSDataStore.new(chef_fs) server_options[:log_level] = Chef::Log.level server_options[:port] = Chef::Config.chef_zero.port Chef::Log.info("Starting chef-zero on port #{Chef::Config.chef_zero.port} with repository at #{server_options[:data_store].chef_fs.fs_description}") @chef_zero_server = ChefZero::Server.new(server_options) @chef_zero_server.start_background Chef::Config.chef_server_url = @chef_zero_server.url end end def self.destroy_server_connectivity if @chef_zero_server @chef_zero_server.stop @chef_zero_server = nil end end # Initializes Chef::Client instance and runs it def run_chef_client Chef::Application.setup_server_connectivity @chef_client = Chef::Client.new( @chef_client_json, :override_runlist => config[:override_runlist] ) @chef_client_json = nil @chef_client.run @chef_client = nil Chef::Application.destroy_server_connectivity end private def apply_config(config_content, config_file_path) Chef::Config.from_string(config_content, config_file_path) rescue Exception => error Chef::Log.fatal("Configuration error #{error.class}: #{error.message}") filtered_trace = error.backtrace.grep(/#{Regexp.escape(config_file_path)}/) filtered_trace.each {|line| Chef::Log.fatal(" " + line )} Chef::Application.fatal!("Aborting due to error in '#{config_file_path}'", 2) end class << self def debug_stacktrace(e) message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}" chef_stacktrace_out = "Generated at #{Time.now.to_s}\n" chef_stacktrace_out += message Chef::FileCache.store("chef-stacktrace.out", chef_stacktrace_out) Chef::Log.fatal("Stacktrace dumped to #{Chef::FileCache.load("chef-stacktrace.out", false)}") Chef::Log.debug(message) true end # Log a fatal error message to both STDERR and the Logger, exit the application def fatal!(msg, err = -1) Chef::Log.fatal(msg) Process.exit err end def exit!(msg, err = -1) Chef::Log.debug(msg) Process.exit err end end end chef-11.8.2/lib/chef/cookbook_version.rb0000644000004100000410000005654512254362222020132 0ustar www-datawww-data# Author:: Adam Jacob () # Author:: Nuo Yan () # Author:: Christopher Walters () # Author:: Tim Hinderliter () # Author:: Seth Falcon () # Author:: Daniel DeLeo () # Copyright:: Copyright 2008-2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'chef/log' require 'chef/node' require 'chef/resource_definition_list' require 'chef/recipe' require 'chef/cookbook/file_vendor' require 'chef/cookbook/metadata' require 'chef/version_class' class Chef # == Chef::CookbookVersion # CookbookVersion is a model object encapsulating the data about a Chef # cookbook. Chef supports maintaining multiple versions of a cookbook on a # single server; each version is represented by a distinct instance of this # class. #-- # TODO: timh/cw: 5-24-2010: mutators for files (e.g., recipe_filenames=, # recipe_filenames.insert) should dirty the manifest so it gets regenerated. class CookbookVersion include Comparable COOKBOOK_SEGMENTS = [ :resources, :providers, :recipes, :definitions, :libraries, :attributes, :files, :templates, :root_files ] attr_accessor :root_dir attr_accessor :definition_filenames attr_accessor :template_filenames attr_accessor :file_filenames attr_accessor :library_filenames attr_accessor :resource_filenames attr_accessor :provider_filenames attr_accessor :root_filenames attr_accessor :name attr_accessor :metadata attr_accessor :metadata_filenames attr_accessor :status # attribute_filenames also has a setter that has non-default # functionality. attr_reader :attribute_filenames # recipe_filenames also has a setter that has non-default # functionality. attr_reader :recipe_filenames attr_reader :recipe_filenames_by_name attr_reader :attribute_filenames_by_short_filename # This is the one and only method that knows how cookbook files' # checksums are generated. def self.checksum_cookbook_file(filepath) Chef::Digester.generate_md5_checksum_for_file(filepath) rescue Errno::ENOENT Chef::Log.debug("File #{filepath} does not exist, so there is no checksum to generate") nil end def self.cache Chef::FileCache end # Creates a new Chef::CookbookVersion object. # # === Returns # object:: Duh. :) def initialize(name) @name = name @frozen = false @attribute_filenames = Array.new @definition_filenames = Array.new @template_filenames = Array.new @file_filenames = Array.new @recipe_filenames = Array.new @recipe_filenames_by_name = Hash.new @library_filenames = Array.new @resource_filenames = Array.new @provider_filenames = Array.new @metadata_filenames = Array.new @root_dir = nil @root_filenames = Array.new @status = :ready @manifest = nil @file_vendor = nil @metadata = Chef::Cookbook::Metadata.new end def version metadata.version end # Indicates if this version is frozen or not. Freezing a coobkook version # indicates that a new cookbook with the same name and version number # shoule def frozen_version? @frozen end def freeze_version @frozen = true end def version=(new_version) manifest["version"] = new_version metadata.version(new_version) end # A manifest is a Mash that maps segment names to arrays of manifest # records (see #preferred_manifest_record for format of manifest records), # as well as describing cookbook metadata. The manifest follows a form # like the following: # # { # :cookbook_name = "apache2", # :version = "1.0", # :name = "Apache 2" # :metadata = ???TODO: timh/cw: 5-24-2010: describe this format, # # :files => [ # { # :name => "afile.rb", # :path => "files/ubuntu-9.10/afile.rb", # :checksum => "2222", # :specificity => "ubuntu-9.10" # }, # ], # :templates => [ manifest_record1, ... ], # ... # } def manifest unless @manifest generate_manifest end @manifest end def manifest=(new_manifest) @manifest = Mash.new new_manifest @checksums = extract_checksums_from_manifest(@manifest) @manifest_records_by_path = extract_manifest_records_by_path(@manifest) COOKBOOK_SEGMENTS.each do |segment| next unless @manifest.has_key?(segment) filenames = @manifest[segment].map{|manifest_record| manifest_record['name']} if segment == :recipes self.recipe_filenames = filenames elsif segment == :attributes self.attribute_filenames = filenames else segment_filenames(segment).clear filenames.each { |filename| segment_filenames(segment) << filename } end end end # Returns a hash of checksums to either nil or the on disk path (which is # done by generate_manifest). def checksums unless @checksums generate_manifest end @checksums end def manifest_records_by_path @manifest_records_by_path || generate_manifest @manifest_records_by_path end def full_name "#{name}-#{version}" end def attribute_filenames=(*filenames) @attribute_filenames = filenames.flatten @attribute_filenames_by_short_filename = filenames_by_name(attribute_filenames) attribute_filenames end ## BACKCOMPAT/DEPRECATED - Remove these and fix breakage before release [DAN - 5/20/2010]## alias :attribute_files :attribute_filenames alias :attribute_files= :attribute_filenames= # Return recipe names in the form of cookbook_name::recipe_name def fully_qualified_recipe_names results = Array.new recipe_filenames_by_name.each_key do |rname| results << "#{name}::#{rname}" end results end def recipe_filenames=(*filenames) @recipe_filenames = filenames.flatten @recipe_filenames_by_name = filenames_by_name(recipe_filenames) recipe_filenames end ## BACKCOMPAT/DEPRECATED - Remove these and fix breakage before release [DAN - 5/20/2010]## alias :recipe_files :recipe_filenames alias :recipe_files= :recipe_filenames= # called from DSL def load_recipe(recipe_name, run_context) unless recipe_filenames_by_name.has_key?(recipe_name) raise Chef::Exceptions::RecipeNotFound, "could not find recipe #{recipe_name} for cookbook #{name}" end Chef::Log.debug("Found recipe #{recipe_name} in cookbook #{name}") recipe = Chef::Recipe.new(name, recipe_name, run_context) recipe_filename = recipe_filenames_by_name[recipe_name] unless recipe_filename raise Chef::Exceptions::RecipeNotFound, "could not find #{recipe_name} files for cookbook #{name}" end recipe.from_file(recipe_filename) recipe end def segment_filenames(segment) unless COOKBOOK_SEGMENTS.include?(segment) raise ArgumentError, "invalid segment #{segment}: must be one of #{COOKBOOK_SEGMENTS.join(', ')}" end case segment.to_sym when :resources @resource_filenames when :providers @provider_filenames when :recipes @recipe_filenames when :libraries @library_filenames when :definitions @definition_filenames when :attributes @attribute_filenames when :files @file_filenames when :templates @template_filenames when :root_files @root_filenames end end # Query whether a template file +template_filename+ is available. File # specificity for the given +node+ is obeyed in the lookup. def has_template_for_node?(node, template_filename) !!find_preferred_manifest_record(node, :templates, template_filename) end # Query whether a cookbook_file file +cookbook_filename+ is available. File # specificity for the given +node+ is obeyed in the lookup. def has_cookbook_file_for_node?(node, cookbook_filename) !!find_preferred_manifest_record(node, :files, cookbook_filename) end # Determine the most specific manifest record for the given # segment/filename, given information in the node. Throws # FileNotFound if there is no such segment and filename in the # manifest. # # A manifest record is a Mash that follows the following form: # { # :name => "example.rb", # :path => "files/default/example.rb", # :specificity => "default", # :checksum => "1234" # } def preferred_manifest_record(node, segment, filename) found_pref = find_preferred_manifest_record(node, segment, filename) if found_pref @manifest_records_by_path[found_pref] else if segment == :files || segment == :templates error_message = "Cookbook '#{name}' (#{version}) does not contain a file at any of these locations:\n" error_locations = [ " #{segment}/#{node[:platform]}-#{node[:platform_version]}/#{filename}", " #{segment}/#{node[:platform]}/#{filename}", " #{segment}/default/#{filename}", ] error_message << error_locations.join("\n") existing_files = segment_filenames(segment) # Show the files that the cookbook does have. If the user made a typo, # hopefully they'll see it here. unless existing_files.empty? error_message << "\n\nThis cookbook _does_ contain: ['#{existing_files.join("','")}']" end raise Chef::Exceptions::FileNotFound, error_message else raise Chef::Exceptions::FileNotFound, "cookbook #{name} does not contain file #{segment}/#{filename}" end end end def preferred_filename_on_disk_location(node, segment, filename, current_filepath=nil) manifest_record = preferred_manifest_record(node, segment, filename) if current_filepath && (manifest_record['checksum'] == self.class.checksum_cookbook_file(current_filepath)) nil else file_vendor.get_filename(manifest_record['path']) end end def relative_filenames_in_preferred_directory(node, segment, dirname) preferences = preferences_for_path(node, segment, dirname) filenames_by_pref = Hash.new preferences.each { |pref| filenames_by_pref[pref] = Array.new } manifest[segment].each do |manifest_record| manifest_record_path = manifest_record[:path] # find the NON SPECIFIC filenames, but prefer them by filespecificity. # For example, if we have a file: # 'files/default/somedir/somefile.conf' we only keep # 'somedir/somefile.conf'. If there is also # 'files/$hostspecific/somedir/otherfiles' that matches the requested # hostname specificity, that directory will win, as it is more specific. # # This is clearly ugly b/c the use case is for remote directory, where # we're just going to make cookbook_files out of these and make the # cookbook find them by filespecificity again. but it's the shortest # path to "success" for now. if manifest_record_path =~ /(#{Regexp.escape(segment.to_s)}\/[^\/]+\/#{Regexp.escape(dirname)})\/.+$/ specificity_dirname = $1 non_specific_path = manifest_record_path[/#{Regexp.escape(segment.to_s)}\/[^\/]+\/#{Regexp.escape(dirname)}\/(.+)$/, 1] # Record the specificity_dirname only if it's in the list of # valid preferences if filenames_by_pref[specificity_dirname] filenames_by_pref[specificity_dirname] << non_specific_path end end end best_pref = preferences.find { |pref| !filenames_by_pref[pref].empty? } raise Chef::Exceptions::FileNotFound, "cookbook #{name} has no directory #{segment}/default/#{dirname}" unless best_pref filenames_by_pref[best_pref] end # Determine the manifest records from the most specific directory # for the given node. See #preferred_manifest_record for a # description of entries of the returned Array. def preferred_manifest_records_for_directory(node, segment, dirname) preferences = preferences_for_path(node, segment, dirname) records_by_pref = Hash.new preferences.each { |pref| records_by_pref[pref] = Array.new } manifest[segment].each do |manifest_record| manifest_record_path = manifest_record[:path] # extract the preference part from the path. if manifest_record_path =~ /(#{Regexp.escape(segment.to_s)}\/[^\/]+\/#{Regexp.escape(dirname)})\/.+$/ # Note the specificy_dirname includes the segment and # dirname argument as above, which is what # preferences_for_path returns. It could be # "files/ubuntu-9.10/dirname", for example. specificity_dirname = $1 # Record the specificity_dirname only if it's in the list of # valid preferences if records_by_pref[specificity_dirname] records_by_pref[specificity_dirname] << manifest_record end end end best_pref = preferences.find { |pref| !records_by_pref[pref].empty? } raise Chef::Exceptions::FileNotFound, "cookbook #{name} (#{version}) has no directory #{segment}/default/#{dirname}" unless best_pref records_by_pref[best_pref] end # Given a node, segment and path (filename or directory name), # return the priority-ordered list of preference locations to # look. def preferences_for_path(node, segment, path) # only files and templates can be platform-specific if segment.to_sym == :files || segment.to_sym == :templates begin platform, version = Chef::Platform.find_platform_and_version(node) rescue ArgumentError => e # Skip platform/version if they were not found by find_platform_and_version if e.message =~ /Cannot find a (?:platform|version)/ platform = "/unknown_platform/" version = "/unknown_platform_version/" else raise end end fqdn = node[:fqdn] # Break version into components, eg: "5.7.1" => [ "5.7.1", "5.7", "5" ] search_versions = [] parts = version.to_s.split('.') parts.size.times do search_versions << parts.join('.') parts.pop end # Most specific to least specific places to find the path search_path = [ File.join(segment.to_s, "host-#{fqdn}", path) ] search_versions.each do |v| search_path << File.join(segment.to_s, "#{platform}-#{v}", path) end search_path << File.join(segment.to_s, platform.to_s, path) search_path << File.join(segment.to_s, "default", path) search_path else [File.join(segment, path)] end end private :preferences_for_path def to_hash result = manifest.dup result['frozen?'] = frozen_version? result['chef_type'] = 'cookbook_version' result.to_hash end def to_json(*a) result = self.to_hash result['json_class'] = self.class.name result.to_json(*a) end def self.json_create(o) cookbook_version = new(o["cookbook_name"]) # We want the Chef::Cookbook::Metadata object to always be inflated cookbook_version.metadata = Chef::Cookbook::Metadata.from_hash(o["metadata"]) cookbook_version.manifest = o # We don't need the following step when we decide to stop supporting deprecated operators in the metadata (e.g. <<, >>) cookbook_version.manifest["metadata"] = Chef::JSONCompat.from_json(cookbook_version.metadata.to_json) cookbook_version.freeze_version if o["frozen?"] cookbook_version end def generate_manifest_with_urls(&url_generator) rendered_manifest = manifest.dup COOKBOOK_SEGMENTS.each do |segment| if rendered_manifest.has_key?(segment) rendered_manifest[segment].each do |manifest_record| url_options = { :cookbook_name => name.to_s, :cookbook_version => version, :checksum => manifest_record["checksum"] } manifest_record["url"] = url_generator.call(url_options) end end end rendered_manifest end def metadata_json_file File.join(root_dir, "metadata.json") end def metadata_rb_file File.join(root_dir, "metadata.rb") end def reload_metadata! if File.exists?(metadata_json_file) metadata.from_json(IO.read(metadata_json_file)) end end ## # REST API ## def self.chef_server_rest Chef::REST.new(Chef::Config[:chef_server_url]) end def chef_server_rest self.class.chef_server_rest end # Return the URL to save (PUT) this object to the server via the # REST api. If there is an existing document on the server and it # is marked frozen, a PUT will result in a 409 Conflict. def save_url "cookbooks/#{name}/#{version}" end # Adds the `force=true` parameter to the upload URL. This allows # the user to overwrite a frozen cookbook (a PUT against the # normal #save_url raises a 409 Conflict in this case). def force_save_url "cookbooks/#{name}/#{version}?force=true" end def destroy chef_server_rest.delete_rest("cookbooks/#{name}/#{version}") self end def self.load(name, version="_latest") version = "_latest" if version == "latest" chef_server_rest.get_rest("cookbooks/#{name}/#{version}") end # The API returns only a single version of each cookbook in the result from the cookbooks method def self.list chef_server_rest.get_rest('cookbooks') end def self.list_all_versions chef_server_rest.get_rest('cookbooks?num_versions=all') end ## # Given a +cookbook_name+, get a list of all versions that exist on the # server. # ===Returns # [String]:: Array of cookbook versions, which are strings like 'x.y.z' # nil:: if the cookbook doesn't exist. an error will also be logged. def self.available_versions(cookbook_name) chef_server_rest.get_rest("cookbooks/#{cookbook_name}")[cookbook_name]["versions"].map do |cb| cb["version"] end rescue Net::HTTPServerException => e if e.to_s =~ /^404/ Chef::Log.error("Cannot find a cookbook named #{cookbook_name}") nil else raise end end # Get the newest version of all cookbooks def self.latest_cookbooks chef_server_rest.get_rest('cookbooks/_latest') end def <=>(o) raise Chef::Exceptions::CookbookVersionNameMismatch if self.name != o.name # FIXME: can we change the interface to the Metadata class such # that metadata.version returns a Chef::Version instance instead # of a string? Chef::Version.new(self.version) <=> Chef::Version.new(o.version) end private def find_preferred_manifest_record(node, segment, filename) preferences = preferences_for_path(node, segment, filename) # ensure that we generate the manifest, which will also generate # @manifest_records_by_path manifest # in order of prefernce, look for the filename in the manifest preferences.find {|preferred_filename| @manifest_records_by_path[preferred_filename] } end # For each filename, produce a mapping of base filename (i.e. recipe name # or attribute file) to on disk location def filenames_by_name(filenames) filenames.select{|filename| filename =~ /\.rb$/}.inject({}){|memo, filename| memo[File.basename(filename, '.rb')] = filename ; memo } end # See #manifest for a description of the manifest return value. # See #preferred_manifest_record for a description an individual manifest record. def generate_manifest manifest = Mash.new({ :recipes => Array.new, :definitions => Array.new, :libraries => Array.new, :attributes => Array.new, :files => Array.new, :templates => Array.new, :resources => Array.new, :providers => Array.new, :root_files => Array.new }) checksums_to_on_disk_paths = {} COOKBOOK_SEGMENTS.each do |segment| segment_filenames(segment).each do |segment_file| next if File.directory?(segment_file) file_name = nil path = nil specificity = "default" if segment == :root_files matcher = segment_file.match(".+/#{Regexp.escape(name.to_s)}/(.+)") file_name = matcher[1] path = file_name elsif segment == :templates || segment == :files matcher = segment_file.match("/#{Regexp.escape(name.to_s)}/(#{Regexp.escape(segment.to_s)}/(.+?)/(.+))") unless matcher Chef::Log.debug("Skipping file #{segment_file}, as it isn't in any of the proper directories (platform-version, platform or default)") Chef::Log.debug("You probably need to move #{segment_file} into the 'default' sub-directory") next end path = matcher[1] specificity = matcher[2] file_name = matcher[3] else matcher = segment_file.match("/#{Regexp.escape(name.to_s)}/(#{Regexp.escape(segment.to_s)}/(.+))") path = matcher[1] file_name = matcher[2] end csum = self.class.checksum_cookbook_file(segment_file) checksums_to_on_disk_paths[csum] = segment_file rs = Mash.new({ :name => file_name, :path => path, :checksum => csum }) rs[:specificity] = specificity manifest[segment] << rs end end manifest[:cookbook_name] = name.to_s manifest[:metadata] = metadata manifest[:version] = metadata.version manifest[:name] = full_name @checksums = checksums_to_on_disk_paths @manifest = manifest @manifest_records_by_path = extract_manifest_records_by_path(manifest) end def file_vendor unless @file_vendor @file_vendor = Chef::Cookbook::FileVendor.create_from_manifest(manifest) end @file_vendor end def extract_checksums_from_manifest(manifest) checksums = {} COOKBOOK_SEGMENTS.each do |segment| next unless manifest.has_key?(segment) manifest[segment].each do |manifest_record| checksums[manifest_record[:checksum]] = nil end end checksums end def extract_manifest_records_by_path(manifest) manifest_records_by_path = {} COOKBOOK_SEGMENTS.each do |segment| next unless manifest.has_key?(segment) manifest[segment].each do |manifest_record| manifest_records_by_path[manifest_record[:path]] = manifest_record end end manifest_records_by_path end end end chef-11.8.2/lib/chef/chef_fs/0000755000004100000410000000000012254362222015610 5ustar www-datawww-datachef-11.8.2/lib/chef/chef_fs/file_pattern.rb0000644000004100000410000002630112254362222020613 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs' require 'chef/chef_fs/path_utils' class Chef module ChefFS # # Represents a glob pattern. This class is designed so that it can # match arbitrary strings, and tell you about partial matches. # # Examples: # * a*z # - Matches abcz # - Does not match ab/cd/ez # - Does not match xabcz # * a**z # - Matches abcz # - Matches ab/cd/ez # # Special characters supported: # * / (and \\ on Windows) - directory separators # * \* - match zero or more characters (but not directory separators) # * \*\* - match zero or more characters, including directory separators # * ? - match exactly one character (not a directory separator) # Only on Unix: # * [abc0-9] - match one of the included characters # * \\ - escape character: match the given character # class FilePattern # Initialize a new FilePattern with the pattern string. # # Raises +ArgumentError+ if empty file pattern is specified def initialize(pattern) @pattern = pattern end # The pattern string. attr_reader :pattern # Reports whether this pattern could match children of path. # If the pattern doesn't match the path up to this point or # if it matches and doesn't allow further children, this will # return false. # # ==== Attributes # # * +path+ - a path to check # # ==== Examples # # abc/def.could_match_children?('abc') == true # abc.could_match_children?('abc') == false # abc/def.could_match_children?('x') == false # a**z.could_match_children?('ab/cd') == true def could_match_children?(path) return false if path == '' # Empty string is not a path argument_is_absolute = !!(path =~ /^#{Chef::ChefFS::PathUtils::regexp_path_separator}/) return false if is_absolute != argument_is_absolute path = path[1,path.length-1] if argument_is_absolute path_parts = Chef::ChefFS::PathUtils::split(path) # If the pattern is shorter than the path (or same size), children will be larger than the pattern, and will not match. return false if regexp_parts.length <= path_parts.length && !has_double_star # If the path doesn't match up to this point, children won't match either. return false if path_parts.zip(regexp_parts).any? { |part,regexp| !regexp.nil? && !regexp.match(part) } # Otherwise, it's possible we could match: the path matches to this point, and the pattern is longer than the path. # TODO There is one edge case where the double star comes after some characters like abc**def--we could check whether the next # bit of path starts with abc in that case. return true end # Returns the immediate child of a path that would be matched # if this FilePattern was applied. If more than one child # could match, this method returns nil. # # ==== Attributes # # * +path+ - The path to look for an exact child name under. # # ==== Returns # # The next directory in the pattern under the given path. # If the directory part could match more than one child, it # returns +nil+. # # ==== Examples # # abc/def.exact_child_name_under('abc') == 'def' # abc/def/ghi.exact_child_name_under('abc') == 'def' # abc/*/ghi.exact_child_name_under('abc') == nil # abc/*/ghi.exact_child_name_under('abc/def') == 'ghi' # abc/**/ghi.exact_child_name_under('abc/def') == nil # # This method assumes +could_match_children?(path)+ is +true+. def exact_child_name_under(path) path = path[1,path.length-1] if !!(path =~ /^#{Chef::ChefFS::PathUtils::regexp_path_separator}/) dirs_in_path = Chef::ChefFS::PathUtils::split(path).length return nil if exact_parts.length <= dirs_in_path return exact_parts[dirs_in_path] end # If this pattern represents an exact path, returns the exact path. # # abc/def.exact_path == 'abc/def' # abc/*def.exact_path == 'abc/def' # abc/x\\yz.exact_path == 'abc/xyz' def exact_path return nil if has_double_star || exact_parts.any? { |part| part.nil? } result = Chef::ChefFS::PathUtils::join(*exact_parts) is_absolute ? Chef::ChefFS::PathUtils::join('', result) : result end # Returns the normalized version of the pattern, with / as the directory # separator, and "." and ".." removed. # # This does not presently change things like \b to b, but in the future # it might. def normalized_pattern calculate @normalized_pattern end # Tell whether this pattern matches absolute, or relative paths def is_absolute calculate @is_absolute end # Returns true+ if this pattern matches the path, false+ otherwise. # # abc/*/def.match?('abc/foo/def') == true # abc/*/def.match?('abc/foo') == false def match?(path) argument_is_absolute = !!(path =~ /^#{Chef::ChefFS::PathUtils::regexp_path_separator}/) return false if is_absolute != argument_is_absolute path = path[1,path.length-1] if argument_is_absolute !!regexp.match(path) end # Returns the string pattern def to_s pattern end # Given a relative file pattern and a directory, makes a new file pattern # starting with the directory. # # FilePattern.relative_to('/usr/local', 'bin/*grok') == FilePattern.new('/usr/local/bin/*grok') # # BUG: this does not support patterns starting with .. def self.relative_to(dir, pattern) return FilePattern.new(pattern) if pattern =~ /^#{Chef::ChefFS::PathUtils::regexp_path_separator}/ FilePattern.new(Chef::ChefFS::PathUtils::join(dir, pattern)) end private def regexp calculate @regexp end def regexp_parts calculate @regexp_parts end def exact_parts calculate @exact_parts end def has_double_star calculate @has_double_star end def calculate if !@regexp @is_absolute = !!(@pattern =~ /^#{Chef::ChefFS::PathUtils::regexp_path_separator}/) full_regexp_parts = [] normalized_parts = [] @regexp_parts = [] @exact_parts = [] @has_double_star = false Chef::ChefFS::PathUtils::split(pattern).each do |part| regexp, exact, has_double_star = FilePattern::pattern_to_regexp(part) if has_double_star @has_double_star = true end # Skip // and /./ (pretend it's not there) if exact == '' || exact == '.' next end # Back up when you see .. (unless the prior part has ** in it, in which case .. must be preserved) if exact == '..' if @is_absolute && normalized_parts.length == 0 # If we are at the root, just pretend the .. isn't there next elsif normalized_parts.length > 0 regexp_prev, exact_prev, has_double_star_prev = FilePattern.pattern_to_regexp(normalized_parts[-1]) if has_double_star_prev raise ArgumentError, ".. overlapping a ** is unsupported" end full_regexp_parts.pop normalized_parts.pop if !@has_double_star @regexp_parts.pop @exact_parts.pop end next end end # Build up the regexp full_regexp_parts << regexp normalized_parts << part if !@has_double_star @regexp_parts << Regexp.new("^#{regexp}$") @exact_parts << exact end end @regexp = Regexp.new("^#{full_regexp_parts.join(Chef::ChefFS::PathUtils::regexp_path_separator)}$") @normalized_pattern = Chef::ChefFS::PathUtils.join(*normalized_parts) @normalized_pattern = Chef::ChefFS::PathUtils.join('', @normalized_pattern) if @is_absolute end end def self.pattern_special_characters if Chef::ChefFS::windows? @pattern_special_characters ||= /(\*\*|\*|\?|[\*\?\.\|\(\)\[\]\{\}\+\\\\\^\$])/ else # Unix also supports character regexes and backslashes @pattern_special_characters ||= /(\\.|\[[^\]]+\]|\*\*|\*|\?|[\*\?\.\|\(\)\[\]\{\}\+\\\\\^\$])/ end @pattern_special_characters end def self.regexp_escape_characters [ '[', '\\', '^', '$', '.', '|', '?', '*', '+', '(', ')', '{', '}' ] end def self.pattern_to_regexp(pattern) regexp = "" exact = "" has_double_star = false pattern.split(pattern_special_characters).each_with_index do |part, index| # Odd indexes from the split are symbols. Even are normal bits. if index % 2 == 0 exact << part if !exact.nil? regexp << part else case part # **, * and ? happen on both platforms. when '**' exact = nil has_double_star = true regexp << '.*' when '*' exact = nil regexp << '[^\/]*' when '?' exact = nil regexp << '.' else if part[0,1] == '\\' && part.length == 2 # backslash escapes are only supported on Unix, and are handled here by leaving the escape on (it means the same thing in a regex) exact << part[1,1] if !exact.nil? if regexp_escape_characters.include?(part[1,1]) regexp << part else regexp << part[1,1] end elsif part[0,1] == '[' && part.length > 1 # [...] happens only on Unix, and is handled here by *not* backslashing (it means the same thing in and out of regex) exact = nil regexp << part else exact += part if !exact.nil? regexp << "\\#{part}" end end end end [regexp, exact, has_double_star] end end end end chef-11.8.2/lib/chef/chef_fs/config.rb0000644000004100000410000001320212254362222017400 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/log' require 'chef/chef_fs/path_utils' class Chef module ChefFS # # Helpers to take Chef::Config and create chef_fs and local_fs from it # class Config def initialize(chef_config = Chef::Config, cwd = Dir.pwd, options = {}) @chef_config = chef_config @cwd = cwd @cookbook_version = options[:cookbook_version] # Default to getting *everything* from the server. if !@chef_config[:repo_mode] if @chef_config[:chef_server_url] =~ /\/+organizations\/.+/ @chef_config[:repo_mode] = 'hosted_everything' else @chef_config[:repo_mode] = 'everything' end end end attr_reader :chef_config attr_reader :cwd attr_reader :cookbook_version def chef_fs @chef_fs ||= create_chef_fs end def create_chef_fs require 'chef/chef_fs/file_system/chef_server_root_dir' Chef::ChefFS::FileSystem::ChefServerRootDir.new("remote", @chef_config, :cookbook_version => @cookbook_version) end def local_fs @local_fs ||= create_local_fs end def create_local_fs require 'chef/chef_fs/file_system/chef_repository_file_system_root_dir' Chef::ChefFS::FileSystem::ChefRepositoryFileSystemRootDir.new(object_paths) end # Returns the given real path's location relative to the server root. # # If chef_repo is /home/jkeiser/chef_repo, # and pwd is /home/jkeiser/chef_repo/cookbooks, # server_path('blah') == '/cookbooks/blah' # server_path('../roles/blah.json') == '/roles/blah' # server_path('../../readme.txt') == nil # server_path('*/*ab*') == '/cookbooks/*/*ab*' # server_path('/home/jkeiser/chef_repo/cookbooks/blah') == '/cookbooks/blah' # server_path('/home/*/chef_repo/cookbooks/blah') == nil # # If there are multiple paths (cookbooks, roles, data bags, etc. can all # have separate paths), and cwd+the path reaches into one of them, we will # return a path relative to that. Otherwise we will return a path to # chef_repo. # # Globs are allowed as well, but globs outside server paths are NOT # (presently) supported. See above examples. TODO support that. # # If the path does not reach into ANY specified directory, nil is returned. def server_path(file_path) pwd = File.expand_path(Dir.pwd) absolute_pwd = Chef::ChefFS::PathUtils.realest_path(File.expand_path(file_path, pwd)) # Check all object paths (cookbooks_dir, data_bags_dir, etc.) object_paths.each_pair do |name, paths| paths.each do |path| realest_path = Chef::ChefFS::PathUtils.realest_path(path) if PathUtils.descendant_of?(absolute_pwd, realest_path) relative_path = Chef::ChefFS::PathUtils::relative_to(absolute_pwd, realest_path) return relative_path == '.' ? "/#{name}" : "/#{name}/#{relative_path}" end end end # Check chef_repo_path Array(@chef_config[:chef_repo_path]).flatten.each do |chef_repo_path| realest_chef_repo_path = Chef::ChefFS::PathUtils.realest_path(chef_repo_path) if absolute_pwd == realest_chef_repo_path return '/' end end nil end # The current directory, relative to server root def base_path @base_path ||= begin if @chef_config[:chef_repo_path] server_path(File.expand_path(@cwd)) else nil end end end # Print the given server path, relative to the current directory def format_path(entry) server_path = entry.path if base_path && server_path[0,base_path.length] == base_path if server_path == base_path return "." elsif server_path[base_path.length,1] == "/" return server_path[base_path.length + 1, server_path.length - base_path.length - 1] elsif base_path == "/" && server_path[0,1] == "/" return server_path[1, server_path.length - 1] end end server_path end private def object_paths @object_paths ||= begin result = {} case @chef_config[:repo_mode] when 'static' object_names = %w(cookbooks data_bags environments roles) when 'hosted_everything' object_names = %w(acls clients cookbooks containers data_bags environments groups nodes roles) else object_names = %w(clients cookbooks data_bags environments nodes roles users) end object_names.each do |object_name| variable_name = "#{object_name[0..-2]}_path" # cookbooks -> cookbook_path paths = Array(@chef_config[variable_name]).flatten result[object_name] = paths.map { |path| File.expand_path(path) } end result end end end end end chef-11.8.2/lib/chef/chef_fs/path_utils.rb0000644000004100000410000000661512254362222020321 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs' require 'pathname' class Chef module ChefFS class PathUtils # If you are in 'source', this is what you would have to type to reach 'dest' # relative_to('/a/b/c/d/e', '/a/b/x/y') == '../../c/d/e' # relative_to('/a/b', '/a/b') == '.' def self.relative_to(dest, source) # Skip past the common parts source_parts = Chef::ChefFS::PathUtils.split(source) dest_parts = Chef::ChefFS::PathUtils.split(dest) i = 0 until i >= source_parts.length || i >= dest_parts.length || source_parts[i] != dest_parts[i] i+=1 end # dot-dot up from 'source' to the common ancestor, then # descend to 'dest' from the common ancestor result = Chef::ChefFS::PathUtils.join(*(['..']*(source_parts.length-i) + dest_parts[i,dest.length-i])) result == '' ? '.' : result end def self.join(*parts) return "" if parts.length == 0 # Determine if it started with a slash absolute = parts[0].length == 0 || parts[0].length > 0 && parts[0] =~ /^#{regexp_path_separator}/ # Remove leading and trailing slashes from each part so that the join will work (and the slash at the end will go away) parts = parts.map { |part| part.gsub(/^\/|\/$/, "") } # Don't join empty bits result = parts.select { |part| part != "" }.join("/") # Put the / back on absolute ? "/#{result}" : result end def self.split(path) path.split(Regexp.new(regexp_path_separator)) end def self.regexp_path_separator Chef::ChefFS::windows? ? '[\/\\\\]' : '/' end # Given a path which may only be partly real (i.e. /x/y/z when only /x exists, # or /x/y/*/blah when /x/y/z/blah exists), call File.realpath on the biggest # part that actually exists. # # If /x is a symlink to /blarghle, and has no subdirectories, then: # PathUtils.realest_path('/x/y/z') == '/blarghle/y/z' # PathUtils.realest_path('/x/*/z') == '/blarghle/*/z' # PathUtils.realest_path('/*/y/z') == '/*/y/z' def self.realest_path(path) path = Pathname.new(path) begin path.realpath.to_s rescue Errno::ENOENT dirname = path.dirname if dirname PathUtils.join(realest_path(dirname), path.basename.to_s) else path.to_s end end end def self.descendant_of?(path, ancestor) path[0,ancestor.length] == ancestor && (ancestor.length == path.length || path[ancestor.length,1] =~ /#{PathUtils.regexp_path_separator}/) end def self.is_absolute?(path) path =~ /^#{regexp_path_separator}/ end end end end chef-11.8.2/lib/chef/chef_fs/knife.rb0000644000004100000410000001022512254362222017231 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef module ChefFS class Knife < Chef::Knife # Workaround for CHEF-3932 def self.deps super do require 'chef/config' require 'chef/chef_fs/parallelizer' require 'chef/chef_fs/config' require 'chef/chef_fs/file_pattern' require 'chef/chef_fs/path_utils' yield end end def self.inherited(c) super # Ensure we always get to do our includes, whether subclass calls deps or not c.deps do end c.options.merge!(options) end option :repo_mode, :long => '--repo-mode MODE', :description => "Specifies the local repository layout. Values: static, everything, hosted_everything. Default: everything/hosted_everything" option :chef_repo_path, :long => '--chef-repo-path PATH', :description => 'Overrides the location of chef repo. Default is specified by chef_repo_path in the config' option :concurrency, :long => '--concurrency THREADS', :description => 'Maximum number of simultaneous requests to send (default: 10)' def configure_chef super Chef::Config[:repo_mode] = config[:repo_mode] if config[:repo_mode] Chef::Config[:concurrency] = config[:concurrency].to_i if config[:concurrency] # --chef-repo-path forcibly overrides all other paths if config[:chef_repo_path] Chef::Config[:chef_repo_path] = config[:chef_repo_path] %w(acl client cookbook container data_bag environment group node role user).each do |variable_name| Chef::Config.delete("#{variable_name}_path".to_sym) end end @chef_fs_config = Chef::ChefFS::Config.new(Chef::Config, Dir.pwd, config) Chef::ChefFS::Parallelizer.threads = (Chef::Config[:concurrency] || 10) - 1 end def chef_fs @chef_fs_config.chef_fs end def create_chef_fs @chef_fs_config.create_chef_fs end def local_fs @chef_fs_config.local_fs end def create_local_fs @chef_fs_config.create_local_fs end def pattern_args @pattern_args ||= pattern_args_from(name_args) end def pattern_args_from(args) args.map { |arg| pattern_arg_from(arg) } end def pattern_arg_from(arg) # TODO support absolute file paths and not just patterns? Too much? # Could be super useful in a world with multiple repo paths if !@chef_fs_config.base_path && !Chef::ChefFS::PathUtils.is_absolute?(arg) # Check if chef repo path is specified to give a better error message ui.error("Attempt to use relative path '#{arg}' when current directory is outside the repository path") exit(1) end Chef::ChefFS::FilePattern.relative_to(@chef_fs_config.base_path, arg) end def format_path(entry) @chef_fs_config.format_path(entry) end def parallelize(inputs, options = {}, &block) Chef::ChefFS::Parallelizer.parallelize(inputs, options, &block) end def discover_repo_dir(dir) %w(.chef cookbooks data_bags environments roles).each do |subdir| return dir if File.directory?(File.join(dir, subdir)) end # If this isn't it, check the parent parent = File.dirname(dir) if parent && parent != dir discover_repo_dir(parent) else nil end end end end end chef-11.8.2/lib/chef/chef_fs/file_system.rb0000644000004100000410000003667412254362222020500 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/path_utils' require 'chef/chef_fs/file_system/default_environment_cannot_be_modified_error' require 'chef/chef_fs/file_system/operation_failed_error' require 'chef/chef_fs/file_system/operation_not_allowed_error' require 'chef/chef_fs/parallelizer' class Chef module ChefFS module FileSystem # Returns a list of all things under (and including) this entry that match the # given pattern. # # ==== Attributes # # * +root+ - Entry to start listing under # * +pattern+ - Chef::ChefFS::FilePattern to match children under # def self.list(root, pattern) Lister.new(root, pattern) end class Lister include Enumerable def initialize(root, pattern) @root = root @pattern = pattern end attr_reader :root attr_reader :pattern def each(&block) list_from(root, &block) end def list_from(entry, &block) # Include self in results if it matches if pattern.match?(entry.path) block.call(entry) end if pattern.could_match_children?(entry.path) # If it's possible that our children could match, descend in and add matches. exact_child_name = pattern.exact_child_name_under(entry.path) # If we've got an exact name, don't bother listing children; just grab the # child with the given name. if exact_child_name exact_child = entry.child(exact_child_name) if exact_child list_from(exact_child, &block) end # Otherwise, go through all children and find any matches elsif entry.dir? results = Parallelizer::parallelize(entry.children, :flatten => true) { |child| Chef::ChefFS::FileSystem.list(child, pattern) } results.each(&block) end end end end # Resolve the given path against the entry, returning # the entry at the end of the path. # # ==== Attributes # # * +entry+ - the entry to start looking under. Relative # paths will be resolved from here. # * +path+ - the path to resolve. If it starts with +/+, # the path will be resolved starting from +entry.root+. # # ==== Examples # # Chef::ChefFS::FileSystem.resolve_path(root_path, 'cookbooks/java/recipes/default.rb') # def self.resolve_path(entry, path) return entry if path.length == 0 return resolve_path(entry.root, path) if path[0,1] == "/" && entry.root != entry if path[0,1] == "/" path = path[1,path.length-1] end result = entry Chef::ChefFS::PathUtils::split(path).each do |part| result = result.child(part) end result end # Copy everything matching the given pattern from src to dest. # # After this method completes, everything in dest matching the # given pattern will look identical to src. # # ==== Attributes # # * +pattern+ - Chef::ChefFS::FilePattern to match children under # * +src_root+ - the root from which things will be copied # * +dest_root+ - the root to which things will be copied # * +recurse_depth+ - the maximum depth to copy things. +nil+ # means infinite depth. 0 means no recursion. # * +options+ - hash of options: # - +purge+ - if +true+, items in +dest+ that are not in +src+ # will be deleted from +dest+. If +false+, these items will # be left alone. # - +force+ - if +true+, matching files are always copied from # +src+ to +dest+. If +false+, they will only be copied if # actually different (which will take time to determine). # - +dry_run+ - if +true+, action will not actually be taken; # things will be printed out instead. # # ==== Examples # # Chef::ChefFS::FileSystem.copy_to(FilePattern.new('/cookbooks'), # chef_fs, local_fs, nil, true) do |message| # puts message # end # def self.copy_to(pattern, src_root, dest_root, recurse_depth, options, ui = nil, format_path = nil) found_result = false error = false parallel_do(list_pairs(pattern, src_root, dest_root)) do |src, dest| found_result = true new_dest_parent = get_or_create_parent(dest, options, ui, format_path) child_error = copy_entries(src, dest, new_dest_parent, recurse_depth, options, ui, format_path) error ||= child_error end if !found_result && pattern.exact_path ui.error "#{pattern}: No such file or directory on remote or local" if ui error = true end error end # Yield entries for children that are in either +a_root+ or +b_root+, with # matching pairs matched up. # # ==== Yields # # Yields matching entries in pairs: # # [ a_entry, b_entry ] # # ==== Example # # Chef::ChefFS::FileSystem.list_pairs(FilePattern.new('**x.txt', a_root, b_root)).each do |a, b| # ... # end # def self.list_pairs(pattern, a_root, b_root) PairLister.new(pattern, a_root, b_root) end class PairLister include Enumerable def initialize(pattern, a_root, b_root) @pattern = pattern @a_root = a_root @b_root = b_root end attr_reader :pattern attr_reader :a_root attr_reader :b_root def each # Make sure everything on the server is also on the filesystem, and diff found_paths = Set.new Chef::ChefFS::FileSystem.list(a_root, pattern).each do |a| found_paths << a.path b = Chef::ChefFS::FileSystem.resolve_path(b_root, a.path) yield [ a, b ] end # Check the outer regex pattern to see if it matches anything on the # filesystem that isn't on the server Chef::ChefFS::FileSystem.list(b_root, pattern).each do |b| if !found_paths.include?(b.path) a = Chef::ChefFS::FileSystem.resolve_path(a_root, b.path) yield [ a, b ] end end end end # Get entries for children of either a or b, with matching pairs matched up. # # ==== Returns # # An array of child pairs. # # [ [ a_child, b_child ], ... ] # # If a child is only in a or only in b, the other child entry will be # retrieved by name (and will most likely be a "nonexistent child"). # # ==== Example # # Chef::ChefFS::FileSystem.child_pairs(a, b).length # def self.child_pairs(a, b) # If both are directories, recurse into them and diff the children instead of returning ourselves. result = [] a_children_names = Set.new a.children.each do |a_child| a_children_names << a_child.name result << [ a_child, b.child(a_child.name) ] end # Check b for children that aren't in a b.children.each do |b_child| if !a_children_names.include?(b_child.name) result << [ a.child(b_child.name), b_child ] end end result end def self.compare(a, b) are_same, a_value, b_value = a.compare_to(b) if are_same.nil? are_same, b_value, a_value = b.compare_to(a) end if are_same.nil? # TODO these reads can be parallelized begin a_value = a.read if a_value.nil? rescue Chef::ChefFS::FileSystem::NotFoundError a_value = :none end begin b_value = b.read if b_value.nil? rescue Chef::ChefFS::FileSystem::NotFoundError b_value = :none end are_same = (a_value == b_value) end [ are_same, a_value, b_value ] end private # Copy two entries (could be files or dirs) def self.copy_entries(src_entry, dest_entry, new_dest_parent, recurse_depth, options, ui, format_path) # A NOTE about this algorithm: # There are cases where this algorithm does too many network requests. # knife upload with a specific filename will first check if the file # exists (a "dir" in the parent) before deciding whether to POST or # PUT it. If we just tried PUT (or POST) and then tried the other if # the conflict failed, we wouldn't need to check existence. # On the other hand, we may already have DONE the request, in which # case we shouldn't waste time trying PUT if we know the file doesn't # exist. # Will need to decide how that works with checksums, though. error = false begin dest_path = format_path.call(dest_entry) if ui src_path = format_path.call(src_entry) if ui if !src_entry.exists? if options[:purge] # If we would not have uploaded it, we will not purge it. if src_entry.parent.can_have_child?(dest_entry.name, dest_entry.dir?) if options[:dry_run] ui.output "Would delete #{dest_path}" if ui else dest_entry.delete(true) ui.output "Deleted extra entry #{dest_path} (purge is on)" if ui end else ui.output ("Not deleting extra entry #{dest_path} (purge is off)") if ui end end elsif !dest_entry.exists? if new_dest_parent.can_have_child?(src_entry.name, src_entry.dir?) # If the entry can do a copy directly from filesystem, do that. if new_dest_parent.respond_to?(:create_child_from) if options[:dry_run] ui.output "Would create #{dest_path}" if ui else new_dest_parent.create_child_from(src_entry) ui.output "Created #{dest_path}" if ui end return end if src_entry.dir? if options[:dry_run] ui.output "Would create #{dest_path}" if ui new_dest_dir = new_dest_parent.child(src_entry.name) else new_dest_dir = new_dest_parent.create_child(src_entry.name, nil) ui.output "Created #{dest_path}" if ui end # Directory creation is recursive. if recurse_depth != 0 parallel_do(src_entry.children) do |src_child| new_dest_child = new_dest_dir.child(src_child.name) child_error = copy_entries(src_child, new_dest_child, new_dest_dir, recurse_depth ? recurse_depth - 1 : recurse_depth, options, ui, format_path) error ||= child_error end end else if options[:dry_run] ui.output "Would create #{dest_path}" if ui else new_dest_parent.create_child(src_entry.name, src_entry.read) ui.output "Created #{dest_path}" if ui end end end else # Both exist. # If the entry can do a copy directly, do that. if dest_entry.respond_to?(:copy_from) if options[:force] || compare(src_entry, dest_entry)[0] == false if options[:dry_run] ui.output "Would update #{dest_path}" if ui else dest_entry.copy_from(src_entry, options) ui.output "Updated #{dest_path}" if ui end end return end # If they are different types, log an error. if src_entry.dir? if dest_entry.dir? # If both are directories, recurse into their children if recurse_depth != 0 parallel_do(child_pairs(src_entry, dest_entry)) do |src_child, dest_child| child_error = copy_entries(src_child, dest_child, dest_entry, recurse_depth ? recurse_depth - 1 : recurse_depth, options, ui, format_path) error ||= child_error end end else # If they are different types. ui.error("File #{src_path} is a directory while file #{dest_path} is a regular file\n") if ui return end else if dest_entry.dir? ui.error("File #{src_path} is a directory while file #{dest_path} is a regular file\n") if ui return else # Both are files! Copy them unless we're sure they are the same.' if options[:diff] == false should_copy = false elsif options[:force] should_copy = true src_value = nil else are_same, src_value, dest_value = compare(src_entry, dest_entry) should_copy = !are_same end if should_copy if options[:dry_run] ui.output "Would update #{dest_path}" if ui else src_value = src_entry.read if src_value.nil? dest_entry.write(src_value) ui.output "Updated #{dest_path}" if ui end end end end end rescue DefaultEnvironmentCannotBeModifiedError => e ui.warn "#{format_path.call(e.entry)} #{e.reason}." if ui rescue OperationFailedError => e ui.error "#{format_path.call(e.entry)} failed to #{e.operation}: #{e.message}" if ui error = true rescue OperationNotAllowedError => e ui.error "#{format_path.call(e.entry)} #{e.reason}." if ui error = true end error end def self.get_or_create_parent(entry, options, ui, format_path) parent = entry.parent if parent && !parent.exists? parent_path = format_path.call(parent) if ui parent_parent = get_or_create_parent(parent, options, ui, format_path) if options[:dry_run] ui.output "Would create #{parent_path}" if ui else parent = parent_parent.create_child(parent.name, nil) ui.output "Created #{parent_path}" if ui end end return parent end def self.parallel_do(enum, options = {}, &block) Chef::ChefFS::Parallelizer.parallelize(enum, options, &block).to_a end end end end chef-11.8.2/lib/chef/chef_fs/command_line.rb0000644000004100000410000002525412254362222020572 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system' require 'chef/chef_fs/file_system/operation_failed_error' require 'chef/chef_fs/file_system/operation_not_allowed_error' require 'chef/util/diff' class Chef module ChefFS module CommandLine def self.diff_print(pattern, a_root, b_root, recurse_depth, output_mode, format_path = nil, diff_filter = nil, ui = nil) if format_path.nil? format_path = proc { |entry| entry.path_for_printing } end get_content = (output_mode != :name_only && output_mode != :name_status) found_match = false diff(pattern, a_root, b_root, recurse_depth, get_content).each do |type, old_entry, new_entry, old_value, new_value, error| found_match = true unless type == :both_nonexistent old_path = format_path.call(old_entry) new_path = format_path.call(new_entry) case type when :common_subdirectories if output_mode != :name_only && output_mode != :name_status yield "Common subdirectories: #{new_path}\n" end when :directory_to_file next if diff_filter && diff_filter !~ /T/ if output_mode == :name_only yield "#{new_path}\n" elsif output_mode == :name_status yield "T\t#{new_path}\n" else yield "File #{old_path} is a directory while file #{new_path} is a regular file\n" end when :file_to_directory next if diff_filter && diff_filter !~ /T/ if output_mode == :name_only yield "#{new_path}\n" elsif output_mode == :name_status yield "T\t#{new_path}\n" else yield "File #{old_path} is a regular file while file #{new_path} is a directory\n" end when :deleted next if diff_filter && diff_filter !~ /D/ if output_mode == :name_only yield "#{new_path}\n" elsif output_mode == :name_status yield "D\t#{new_path}\n" elsif old_value result = "diff --knife #{old_path} #{new_path}\n" result << "deleted file\n" result << diff_text(old_path, '/dev/null', old_value, '') yield result else yield "Only in #{format_path.call(old_entry.parent)}: #{old_entry.name}\n" end when :added next if diff_filter && diff_filter !~ /A/ if output_mode == :name_only yield "#{new_path}\n" elsif output_mode == :name_status yield "A\t#{new_path}\n" elsif new_value result = "diff --knife #{old_path} #{new_path}\n" result << "new file\n" result << diff_text('/dev/null', new_path, '', new_value) yield result else yield "Only in #{format_path.call(new_entry.parent)}: #{new_entry.name}\n" end when :modified next if diff_filter && diff_filter !~ /M/ if output_mode == :name_only yield "#{new_path}\n" elsif output_mode == :name_status yield "M\t#{new_path}\n" else result = "diff --knife #{old_path} #{new_path}\n" result << diff_text(old_path, new_path, old_value, new_value) yield result end when :both_nonexistent when :added_cannot_upload when :deleted_cannot_download when :same # Skip these silently when :error if error.is_a?(Chef::ChefFS::FileSystem::OperationFailedError) ui.error "#{format_path.call(error.entry)} failed to #{error.operation}: #{error.message}" if ui error = true elsif error.is_a?(Chef::ChefFS::FileSystem::OperationNotAllowedError) ui.error "#{format_path.call(error.entry)} #{error.reason}." if ui else raise error end end end if !found_match ui.error "#{pattern}: No such file or directory on remote or local" if ui error = true end error end def self.diff(pattern, old_root, new_root, recurse_depth, get_content) Chef::ChefFS::Parallelizer.parallelize(Chef::ChefFS::FileSystem.list_pairs(pattern, old_root, new_root), :flatten => true) do |old_entry, new_entry| diff_entries(old_entry, new_entry, recurse_depth, get_content) end end # Diff two known entries (could be files or dirs) def self.diff_entries(old_entry, new_entry, recurse_depth, get_content) # If both are directories if old_entry.dir? if new_entry.dir? if recurse_depth == 0 return [ [ :common_subdirectories, old_entry, new_entry ] ] else return Chef::ChefFS::Parallelizer.parallelize(Chef::ChefFS::FileSystem.child_pairs(old_entry, new_entry), :flatten => true) do |old_child, new_child| Chef::ChefFS::CommandLine.diff_entries(old_child, new_child, recurse_depth ? recurse_depth - 1 : nil, get_content) end end # If old is a directory and new is a file elsif new_entry.exists? return [ [ :directory_to_file, old_entry, new_entry ] ] # If old is a directory and new does not exist elsif new_entry.parent.can_have_child?(old_entry.name, old_entry.dir?) return [ [ :deleted, old_entry, new_entry ] ] # If the new entry does not and *cannot* exist, report that. else return [ [ :new_cannot_upload, old_entry, new_entry ] ] end # If new is a directory and old is a file elsif new_entry.dir? if old_entry.exists? return [ [ :file_to_directory, old_entry, new_entry ] ] # If new is a directory and old does not exist elsif old_entry.parent.can_have_child?(new_entry.name, new_entry.dir?) return [ [ :added, old_entry, new_entry ] ] # If the new entry does not and *cannot* exist, report that. else return [ [ :old_cannot_upload, old_entry, new_entry ] ] end # Neither is a directory, so they are diffable with file diff else are_same, old_value, new_value = Chef::ChefFS::FileSystem.compare(old_entry, new_entry) if are_same if old_value == :none return [ [ :both_nonexistent, old_entry, new_entry ] ] else return [ [ :same, old_entry, new_entry ] ] end else if old_value == :none old_exists = false elsif old_value.nil? old_exists = old_entry.exists? else old_exists = true end if new_value == :none new_exists = false elsif new_value.nil? new_exists = new_entry.exists? else new_exists = true end # If one of the files doesn't exist, we only want to print the diff if the # other file *could be uploaded/downloaded*. if !old_exists && !old_entry.parent.can_have_child?(new_entry.name, new_entry.dir?) return [ [ :old_cannot_upload, old_entry, new_entry ] ] end if !new_exists && !new_entry.parent.can_have_child?(old_entry.name, old_entry.dir?) return [ [ :new_cannot_upload, old_entry, new_entry ] ] end if get_content # If we haven't read the values yet, get them now so that they can be diffed begin old_value = old_entry.read if old_value.nil? rescue Chef::ChefFS::FileSystem::NotFoundError old_value = :none end begin new_value = new_entry.read if new_value.nil? rescue Chef::ChefFS::FileSystem::NotFoundError new_value = :none end end if old_value == :none || (old_value == nil && !old_entry.exists?) return [ [ :added, old_entry, new_entry, old_value, new_value ] ] elsif new_value == :none return [ [ :deleted, old_entry, new_entry, old_value, new_value ] ] else return [ [ :modified, old_entry, new_entry, old_value, new_value ] ] end end end rescue Chef::ChefFS::FileSystem::FileSystemError => e return [ [ :error, old_entry, new_entry, nil, nil, e ] ] end private def self.sort_keys(json_object) if json_object.is_a?(Array) json_object.map { |o| sort_keys(o) } elsif json_object.is_a?(Hash) new_hash = {} json_object.keys.sort.each { |key| new_hash[key] = sort_keys(json_object[key]) } new_hash else json_object end end def self.canonicalize_json(json_text) parsed_json = JSON.parse(json_text, :create_additions => false) sorted_json = sort_keys(parsed_json) JSON.pretty_generate(sorted_json) end def self.diff_text(old_path, new_path, old_value, new_value) # Copy to tempfiles before diffing # TODO don't copy things that are already in files! Or find an in-memory diff algorithm begin new_tempfile = Tempfile.new("new") new_tempfile.write(new_value) new_tempfile.close begin old_tempfile = Tempfile.new("old") old_tempfile.write(old_value) old_tempfile.close result = Chef::Util::Diff.new.udiff(old_tempfile.path, new_tempfile.path) result = result.gsub(/^--- #{old_tempfile.path}/, "--- #{old_path}") result = result.gsub(/^\+\+\+ #{new_tempfile.path}/, "+++ #{new_path}") result ensure old_tempfile.close! end ensure new_tempfile.close! end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/0000755000004100000410000000000012254362222020133 5ustar www-datawww-datachef-11.8.2/lib/chef/chef_fs/file_system/cookbook_file.rb0000644000004100000410000000437612254362222023277 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/base_fs_object' require 'chef/http/simple' require 'digest/md5' class Chef module ChefFS module FileSystem class CookbookFile < BaseFSObject def initialize(name, parent, file) super(name, parent) @file = file end attr_reader :file def checksum file[:checksum] end def read begin tmpfile = rest.streaming_request(file[:url]) rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "Timeout reading #{file[:url]}: #{e}" rescue Net::HTTPServerException => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "#{e.message} retrieving #{file[:url]}" end begin tmpfile.open tmpfile.read ensure tmpfile.close! end end def rest parent.rest end def compare_to(other) other_value = nil if other.respond_to?(:checksum) other_checksum = other.checksum else begin other_value = other.read rescue Chef::ChefFS::FileSystem::NotFoundError return [ false, nil, :none ] end other_checksum = calc_checksum(other_value) end [ checksum == other_checksum, nil, other_value ] end private def calc_checksum(value) Digest::MD5.hexdigest(value) end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/acl_entry.rb0000644000004100000410000000412112254362222022436 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/rest_list_entry' require 'chef/chef_fs/file_system/not_found_error' require 'chef/chef_fs/file_system/operation_not_allowed_error' require 'chef/chef_fs/file_system/operation_failed_error' class Chef module ChefFS module FileSystem class AclEntry < RestListEntry PERMISSIONS = %w(create read update delete grant) def api_path "#{super}/_acl" end def delete(recurse) raise Chef::ChefFS::FileSystem::OperationNotAllowedError.new(:delete, self, e), "ACLs cannot be deleted." end def write(file_contents) # ACL writes are fun. acls = data_handler.normalize(JSON.parse(file_contents, :create_additions => false), self) PERMISSIONS.each do |permission| begin rest.put("#{api_path}/#{permission}", { permission => acls[permission] }) rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Timeout writing: #{e}" rescue Net::HTTPServerException => e if e.response.code == "404" raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e) else raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "HTTP error writing: #{e}" end end end end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/nodes_dir.rb0000644000004100000410000000374212254362222022434 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/base_fs_dir' require 'chef/chef_fs/file_system/rest_list_entry' require 'chef/chef_fs/file_system/not_found_error' require 'chef/chef_fs/data_handler/node_data_handler' class Chef module ChefFS module FileSystem class NodesDir < RestListDir def initialize(parent) super("nodes", parent, nil, Chef::ChefFS::DataHandler::NodeDataHandler.new) end # Identical to RestListDir.children, except supports environments def children begin @children ||= root.get_json(env_api_path).keys.sort.map do |key| _make_child_entry("#{key}.json", true) end rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "Timeout retrieving children: #{e}" rescue Net::HTTPServerException => e if $!.response.code == "404" raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!) else raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "HTTP error retrieving children: #{e}" end end end def env_api_path environment ? "environments/#{environment}/#{api_path}" : api_path end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/chef_repository_file_system_acls_dir.rb0000644000004100000410000000244312254362222030132 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/chef_repository_file_system_entry' require 'chef/chef_fs/file_system/acls_dir' require 'chef/chef_fs/data_handler/acl_data_handler' class Chef module ChefFS module FileSystem class ChefRepositoryFileSystemAclsDir < ChefRepositoryFileSystemEntry def initialize(name, parent, path = nil) super(name, parent, path, Chef::ChefFS::DataHandler::AclDataHandler.new) end def can_have_child?(name, is_dir) is_dir ? Chef::ChefFS::FileSystem::AclsDir::ENTITY_TYPES.include?(name) : name == 'organization.json' end end end end endchef-11.8.2/lib/chef/chef_fs/file_system/chef_server_root_dir.rb0000644000004100000410000001042312254362222024654 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/server_api' require 'chef/chef_fs/file_system/acls_dir' require 'chef/chef_fs/file_system/base_fs_dir' require 'chef/chef_fs/file_system/rest_list_dir' require 'chef/chef_fs/file_system/cookbooks_dir' require 'chef/chef_fs/file_system/data_bags_dir' require 'chef/chef_fs/file_system/nodes_dir' require 'chef/chef_fs/file_system/environments_dir' require 'chef/chef_fs/data_handler/client_data_handler' require 'chef/chef_fs/data_handler/role_data_handler' require 'chef/chef_fs/data_handler/user_data_handler' require 'chef/chef_fs/data_handler/group_data_handler' require 'chef/chef_fs/data_handler/container_data_handler' class Chef module ChefFS module FileSystem class ChefServerRootDir < BaseFSDir def initialize(root_name, chef_config, options = {}) super("", nil) @chef_server_url = chef_config[:chef_server_url] @chef_username = chef_config[:node_name] @chef_private_key = chef_config[:client_key] @environment = chef_config[:environment] @repo_mode = chef_config[:repo_mode] @root_name = root_name @cookbook_version = options[:cookbook_version] # Used in knife diff and download for server cookbook version end attr_reader :chef_server_url attr_reader :chef_username attr_reader :chef_private_key attr_reader :environment attr_reader :repo_mode attr_reader :cookbook_version def fs_description "Chef server at #{chef_server_url} (user #{chef_username}), repo_mode = #{repo_mode}" end def rest Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key, :raw_output => true) end def get_json(path) Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key).get(path) end def chef_rest Chef::REST.new(chef_server_url, chef_username, chef_private_key) end def api_path "" end def path_for_printing "#{@root_name}/" end def can_have_child?(name, is_dir) is_dir && children.any? { |child| child.name == name } end def org @org ||= if URI.parse(chef_server_url).path =~ /^\/+organizations\/+([^\/]+)$/ $1 else nil end end def children @children ||= begin result = [ CookbooksDir.new(self), DataBagsDir.new(self), EnvironmentsDir.new(self), RestListDir.new("roles", self, nil, Chef::ChefFS::DataHandler::RoleDataHandler.new) ] if repo_mode == 'hosted_everything' result += [ AclsDir.new(self), RestListDir.new("clients", self, nil, Chef::ChefFS::DataHandler::ClientDataHandler.new), RestListDir.new("containers", self, nil, Chef::ChefFS::DataHandler::ContainerDataHandler.new), RestListDir.new("groups", self, nil, Chef::ChefFS::DataHandler::GroupDataHandler.new), NodesDir.new(self) ] elsif repo_mode != 'static' result += [ RestListDir.new("clients", self, nil, Chef::ChefFS::DataHandler::ClientDataHandler.new), NodesDir.new(self), RestListDir.new("users", self, nil, Chef::ChefFS::DataHandler::UserDataHandler.new) ] end result.sort_by { |child| child.name } end end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/data_bag_dir.rb0000644000004100000410000000447212254362222023047 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/rest_list_dir' require 'chef/chef_fs/file_system/not_found_error' require 'chef/chef_fs/file_system/must_delete_recursively_error' require 'chef/chef_fs/data_handler/data_bag_item_data_handler' class Chef module ChefFS module FileSystem class DataBagDir < RestListDir def initialize(name, parent, exists = nil) super(name, parent, nil, Chef::ChefFS::DataHandler::DataBagItemDataHandler.new) @exists = nil end def dir? exists? end def read # This will only be called if dir? is false, which means exists? is false. raise Chef::ChefFS::FileSystem::NotFoundError.new(self) end def exists? if @exists.nil? @exists = parent.children.any? { |child| child.name == name } end @exists end def delete(recurse) if !recurse raise NotFoundError.new(self) if !exists? raise MustDeleteRecursivelyError.new(self), "#{path_for_printing} must be deleted recursively" end begin rest.delete(api_path) rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}" rescue Net::HTTPServerException => e if e.response.code == "404" raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e) else raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "HTTP error deleting: #{e}" end end end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/memory_file.rb0000644000004100000410000000054412254362222022772 0ustar www-datawww-datarequire 'chef/chef_fs/file_system/base_fs_object' class Chef module ChefFS module FileSystem class MemoryFile < Chef::ChefFS::FileSystem::BaseFSObject def initialize(name, parent, value) super(name, parent) @value = value end def read return @value end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/environments_dir.rb0000644000004100000410000000404212254362222024045 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/base_fs_dir' require 'chef/chef_fs/file_system/rest_list_entry' require 'chef/chef_fs/file_system/not_found_error' require 'chef/chef_fs/file_system/default_environment_cannot_be_modified_error' require 'chef/chef_fs/data_handler/environment_data_handler' class Chef module ChefFS module FileSystem class EnvironmentsDir < RestListDir def initialize(parent) super("environments", parent, nil, Chef::ChefFS::DataHandler::EnvironmentDataHandler.new) end def _make_child_entry(name, exists = nil) if name == '_default.json' DefaultEnvironmentEntry.new(name, self, exists) else super end end class DefaultEnvironmentEntry < RestListEntry def initialize(name, parent, exists = nil) super(name, parent) @exists = exists end def delete(recurse) raise NotFoundError.new(self) if !exists? raise DefaultEnvironmentCannotBeModifiedError.new(:delete, self), "#{path_for_printing} cannot be deleted." end def write(file_contents) raise NotFoundError.new(self) if !exists? raise DefaultEnvironmentCannotBeModifiedError.new(:write, self), "#{path_for_printing} cannot be updated." end end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/file_system_error.rb0000644000004100000410000000170612254362222024220 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef module ChefFS module FileSystem class FileSystemError < StandardError def initialize(entry, cause = nil) @entry = entry @cause = cause end attr_reader :entry attr_reader :cause end end end end chef-11.8.2/lib/chef/chef_fs/file_system/data_bags_dir.rb0000644000004100000410000000521612254362222023227 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/rest_list_dir' require 'chef/chef_fs/file_system/data_bag_dir' class Chef module ChefFS module FileSystem class DataBagsDir < RestListDir def initialize(parent) super("data_bags", parent, "data") end def child(name) result = @children.select { |child| child.name == name }.first if @children result || DataBagDir.new(name, self) end def children begin @children ||= root.get_json(api_path).keys.sort.map do |entry| DataBagDir.new(entry, self, true) end rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "Timeout getting children: #{e}" rescue Net::HTTPServerException => e if e.response.code == "404" raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e) else raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "HTTP error getting children: #{e}" end end end def can_have_child?(name, is_dir) is_dir end def create_child(name, file_contents) begin rest.post(api_path, { 'name' => name }) rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "Timeout creating child '#{name}': #{e}" rescue Net::HTTPServerException => e if e.response.code == "409" raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self, e), "Cannot create #{name} under #{path}: already exists" else raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "HTTP error creating child '#{name}': #{e}" end end @children = nil DataBagDir.new(name, self, true) end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/memory_root.rb0000644000004100000410000000070512254362222023035 0ustar www-datawww-datarequire 'chef/chef_fs/file_system/memory_dir' class Chef module ChefFS module FileSystem class MemoryRoot < MemoryDir def initialize(pretty_name, cannot_be_in_regex = nil) super('', nil) @pretty_name = pretty_name @cannot_be_in_regex = cannot_be_in_regex end attr_reader :cannot_be_in_regex def path_for_printing @pretty_name end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/nonexistent_fs_object.rb0000644000004100000410000000200112254362222025045 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/base_fs_object' require 'chef/chef_fs/file_system/not_found_error' class Chef module ChefFS module FileSystem class NonexistentFSObject < BaseFSObject def initialize(name, parent) super end def exists? false end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/cookbook_dir.rb0000644000004100000410000002074412254362222023133 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/rest_list_dir' require 'chef/chef_fs/file_system/cookbook_subdir' require 'chef/chef_fs/file_system/cookbook_file' require 'chef/chef_fs/file_system/not_found_error' require 'chef/cookbook_version' require 'chef/cookbook_uploader' class Chef module ChefFS module FileSystem class CookbookDir < BaseFSDir def initialize(name, parent, options = {}) super(name, parent) @exists = options[:exists] # If the name is apache2-1.0.0 and versioned_cookbooks is on, we know # the actual cookbook_name and version. if Chef::Config[:versioned_cookbooks] if name =~ VALID_VERSIONED_COOKBOOK_NAME @cookbook_name = $1 @version = $2 else @exists = false end else @cookbook_name = name @version = root.cookbook_version # nil unless --cookbook-version specified in download/diff end end attr_reader :cookbook_name, :version COOKBOOK_SEGMENT_INFO = { :attributes => { :ruby_only => true }, :definitions => { :ruby_only => true }, :recipes => { :ruby_only => true }, :libraries => { :ruby_only => true }, :templates => { :recursive => true }, :files => { :recursive => true }, :resources => { :ruby_only => true, :recursive => true }, :providers => { :ruby_only => true, :recursive => true }, :root_files => { } } # See Erchef code # https://github.com/opscode/chef_objects/blob/968a63344d38fd507f6ace05f73d53e9cd7fb043/src/chef_regex.erl#L94 VALID_VERSIONED_COOKBOOK_NAME = /^([.a-zA-Z0-9_-]+)-(\d+\.\d+\.\d+)$/ def add_child(child) @children << child end def api_path "#{parent.api_path}/#{cookbook_name}/#{version || "_latest"}" end def child(name) # Since we're ignoring the rules and doing a network request here, # we need to make sure we don't rethrow the exception. (child(name) # is not supposed to fail.) begin result = children.select { |child| child.name == name }.first return result if result rescue Chef::ChefFS::FileSystem::NotFoundError end return NonexistentFSObject.new(name, self) end def can_have_child?(name, is_dir) # A cookbook's root may not have directories unless they are segment directories return name != 'root_files' && COOKBOOK_SEGMENT_INFO.keys.include?(name.to_sym) if is_dir return true end def children if @children.nil? @children = [] manifest = chef_object.manifest COOKBOOK_SEGMENT_INFO.each do |segment, segment_info| next unless manifest.has_key?(segment) # Go through each file in the manifest for the segment, and # add cookbook subdirs and files for it. manifest[segment].each do |segment_file| parts = segment_file[:path].split('/') # Get or create the path to the file container = self parts[0,parts.length-1].each do |part| old_container = container container = old_container.children.select { |child| part == child.name }.first if !container container = CookbookSubdir.new(part, old_container, segment_info[:ruby_only], segment_info[:recursive]) old_container.add_child(container) end end # Create the file itself container.add_child(CookbookFile.new(parts[parts.length-1], container, segment_file)) end end @children = @children.sort_by { |c| c.name } end @children end def dir? exists? end def delete(recurse) if recurse begin rest.delete(api_path) rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}" rescue Net::HTTPServerException if $!.response.code == "404" raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!) else raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "HTTP error deleting: #{e}" end end else raise NotFoundError.new(self) if !exists? raise MustDeleteRecursivelyError.new(self), "#{path_for_printing} must be deleted recursively" end end # In versioned cookbook mode, actually check if the version exists # Probably want to cache this. def exists? if @exists.nil? @exists = parent.children.any? { |child| child.name == name } end @exists end def compare_to(other) if !other.dir? return [ !exists?, nil, nil ] end are_same = true Chef::ChefFS::CommandLine::diff_entries(self, other, nil, :name_only).each do |type, old_entry, new_entry| if [ :directory_to_file, :file_to_directory, :deleted, :added, :modified ].include?(type) are_same = false end end [ are_same, nil, nil ] end def copy_from(other, options = {}) parent.upload_cookbook_from(other, options) end def rest parent.rest end def chef_object # We cheat and cache here, because it seems like a good idea to keep # the cookbook view consistent with the directory structure. return @chef_object if @chef_object # The negative (not found) response is cached if @could_not_get_chef_object raise Chef::ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object) end begin # We want to fail fast, for now, because of the 500 issue :/ # This will make things worse for parallelism, a little, because # Chef::Config is global and this could affect other requests while # this request is going on. (We're not parallel yet, but we will be.) # Chef bug http://tickets.opscode.com/browse/CHEF-3066 old_retry_count = Chef::Config[:http_retry_count] begin Chef::Config[:http_retry_count] = 0 @chef_object ||= Chef::CookbookVersion.json_create(root.get_json(api_path)) ensure Chef::Config[:http_retry_count] = old_retry_count end rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "Timeout reading: #{e}" rescue Net::HTTPServerException => e if e.response.code == "404" @could_not_get_chef_object = e raise Chef::ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object) else raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "HTTP error reading: #{e}" end # Chef bug http://tickets.opscode.com/browse/CHEF-3066 ... instead of 404 we get 500 right now. # Remove this when that bug is fixed. rescue Net::HTTPFatalError => e if e.response.code == "500" @could_not_get_chef_object = e raise Chef::ChefFS::FileSystem::NotFoundError.new(self, @could_not_get_chef_object) else raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "HTTP error reading: #{e}" end end end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/operation_failed_error.rb0000644000004100000410000000234012254362222025174 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/file_system_error' class Chef module ChefFS module FileSystem class OperationFailedError < FileSystemError def initialize(operation, entry, cause = nil) super(entry, cause) @operation = operation end def message if cause && cause.is_a?(Net::HTTPExceptions) && cause.response.code == "400" "#{super} cause: #{cause.response.body}" else super end end attr_reader :operation end end end end chef-11.8.2/lib/chef/chef_fs/file_system/acl_dir.rb0000644000004100000410000000406112254362222022056 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/base_fs_dir' require 'chef/chef_fs/file_system/acl_entry' require 'chef/chef_fs/file_system/operation_not_allowed_error' class Chef module ChefFS module FileSystem class AclDir < BaseFSDir def api_path parent.parent.child(name).api_path end def child(name) result = @children.select { |child| child.name == name }.first if @children result ||= can_have_child?(name, false) ? AclEntry.new(name, self) : NonexistentFSObject.new(name, self) end def can_have_child?(name, is_dir) name =~ /\.json$/ && !is_dir end def children if @children.nil? # Grab the ACTUAL children (/nodes, /containers, etc.) and get their names names = parent.parent.child(name).children.map { |child| child.dir? ? "#{child.name}.json" : child.name } @children = names.map { |name| AclEntry.new(name, self, true) } end @children end def create_child(name, file_contents) raise OperationNotAllowedError.new(:create_child, self), "ACLs can only be updated, and can only be created when the corresponding object is created." end def data_handler parent.data_handler end def rest parent.rest end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/default_environment_cannot_be_modified_error.rb0000644000004100000410000000215412254362222031613 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/operation_not_allowed_error' class Chef module ChefFS module FileSystem class DefaultEnvironmentCannotBeModifiedError < OperationNotAllowedError def initialize(operation, entry, cause = nil) super(operation, entry, cause) end def reason result = super result + " (default environment cannot be modified)" end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir.rb0000644000004100000410000000456112254362222031204 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/chef_repository_file_system_entry' require 'chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir' require 'chef/cookbook/chefignore' class Chef module ChefFS module FileSystem class ChefRepositoryFileSystemCookbooksDir < ChefRepositoryFileSystemEntry def initialize(name, parent, file_path) super(name, parent, file_path) begin @chefignore = Chef::Cookbook::Chefignore.new(self.file_path) rescue Errno::EISDIR rescue Errno::EACCES # Work around a bug in Chefignore when chefignore is a directory end end attr_reader :chefignore def children begin Dir.entries(file_path).sort. select { |child_name| can_have_child?(child_name, File.directory?(File.join(file_path, child_name))) }. map { |child_name| make_child(child_name) }. select do |entry| # empty cookbooks and cookbook directories are ignored if entry.children.size == 0 Chef::Log.warn("Cookbook '#{entry.name}' is empty or entirely chefignored at #{entry.path_for_printing}") false else true end end rescue Errno::ENOENT raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!) end end def can_have_child?(name, is_dir) is_dir && !name.start_with?('.') end protected def make_child(child_name) ChefRepositoryFileSystemCookbookDir.new(child_name, self) end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/base_fs_dir.rb0000644000004100000410000000250212254362222022717 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/base_fs_object' require 'chef/chef_fs/file_system/nonexistent_fs_object' class Chef module ChefFS module FileSystem class BaseFSDir < BaseFSObject def initialize(name, parent) super end def dir? true end # Override child(name) to provide a child object by name without the network read def child(name) children.select { |child| child.name == name }.first || NonexistentFSObject.new(name, self) end def can_have_child?(name, is_dir) true end # Abstract: children end end end end chef-11.8.2/lib/chef/chef_fs/file_system/cookbook_subdir.rb0000644000004100000410000000264212254362222023642 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/base_fs_dir' class Chef module ChefFS module FileSystem class CookbookSubdir < BaseFSDir def initialize(name, parent, ruby_only, recursive) super(name, parent) @children = [] @ruby_only = ruby_only @recursive = recursive end attr_reader :versions attr_reader :children def add_child(child) @children << child end def can_have_child?(name, is_dir) if is_dir return false if !@recursive else return false if @ruby_only && name !~ /\.rb$/ end true end def rest parent.rest end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/rest_list_dir.rb0000644000004100000410000001004512254362222023326 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/base_fs_dir' require 'chef/chef_fs/file_system/rest_list_entry' require 'chef/chef_fs/file_system/not_found_error' class Chef module ChefFS module FileSystem class RestListDir < BaseFSDir def initialize(name, parent, api_path = nil, data_handler = nil) super(name, parent) @api_path = api_path || (parent.api_path == "" ? name : "#{parent.api_path}/#{name}") @data_handler = data_handler end attr_reader :api_path attr_reader :data_handler def child(name) result = @children.select { |child| child.name == name }.first if @children result ||= can_have_child?(name, false) ? _make_child_entry(name) : NonexistentFSObject.new(name, self) end def can_have_child?(name, is_dir) name =~ /\.json$/ && !is_dir end def children begin @children ||= root.get_json(api_path).keys.sort.map do |key| _make_child_entry("#{key}.json", true) end rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "Timeout retrieving children: #{e}" rescue Net::HTTPServerException => e if $!.response.code == "404" raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!) else raise Chef::ChefFS::FileSystem::OperationFailedError.new(:children, self, e), "HTTP error retrieving children: #{e}" end end end def create_child(name, file_contents) begin object = JSON.parse(file_contents, :create_additions => false) rescue JSON::ParserError => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "Parse error reading JSON creating child '#{name}': #{e}" end result = _make_child_entry(name, true) if data_handler object = data_handler.normalize_for_post(object, result) data_handler.verify_integrity(object, result) do |error| raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self), "Error creating '#{name}': #{error}" end end begin rest.post(api_path, object) rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "Timeout creating '#{name}': #{e}" rescue Net::HTTPServerException => e if e.response.code == "404" raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e) elsif $!.response.code == "409" raise Chef::ChefFS::FileSystem::AlreadyExistsError.new(:create_child, self, e), "Failure creating '#{name}': #{path}/#{name} already exists" else raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "Failure creating '#{name}': #{e.message}" end end @children = nil result end def org parent.org end def environment parent.environment end def rest parent.rest end def _make_child_entry(name, exists = nil) RestListEntry.new(name, self, exists) end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/base_fs_object.rb0000644000004100000410000001456112254362222023417 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/path_utils' require 'chef/chef_fs/file_system/operation_not_allowed_error' class Chef module ChefFS module FileSystem class BaseFSObject def initialize(name, parent) @parent = parent @name = name if parent @path = Chef::ChefFS::PathUtils::join(parent.path, name) else if name != '' raise ArgumentError, "Name of root object must be empty string: was '#{name}' instead" end @path = '/' end end attr_reader :name attr_reader :parent attr_reader :path # Override this if you have a special comparison algorithm that can tell # you whether this entry is the same as another--either a quicker or a # more reliable one. Callers will use this to decide whether to upload, # download or diff an object. # # You should not override this if you're going to do the standard # +self.read == other.read+. If you return +nil+, the caller will call # +other.compare_to(you)+ instead. Give them a chance :) # # ==== Parameters # # * +other+ - the entry to compare to # # ==== Returns # # * +[ are_same, value, other_value ]+ # +are_same+ may be +true+, +false+ or +nil+ (which means "don't know"). # +value+ and +other_value+ must either be the text of +self+ or +other+, # +:none+ (if the entry does not exist or has no value) or +nil+ if the # value was not retrieved. # * +nil+ if a definitive answer cannot be had and nothing was retrieved. # # ==== Example # # are_same, value, other_value = entry.compare_to(other) # if are_same.nil? # are_same, other_value, value = other.compare_to(entry) # end # if are_same.nil? # value = entry.read if value.nil? # other_value = entry.read if other_value.nil? # are_same = (value == other_value) # end def compare_to(other) nil end # Override can_have_child? to report whether a given file *could* be added # to this directory. (Some directories can't have subdirs, some can only have .json # files, etc.) def can_have_child?(name, is_dir) false end # Get a child of this entry with the given name. This MUST always # return a child, even if it is NonexistentFSObject. Overriders should # take caution not to do expensive network requests to get the list of # children to fulfill this request, unless absolutely necessary here; it # is intended as a quick way to traverse a hierarchy. # # For example, knife show /data_bags/x/y.json will call # root.child('data_bags').child('x').child('y.json'), which can then # directly perform a network request to retrieve the y.json data bag. No # network request was necessary to retrieve def child(name) NonexistentFSObject.new(name, self) end # Override children to report your *actual* list of children as an array. def children raise NotFoundError.new(self) if !exists? [] end # Expand this entry into a chef object (Chef::Role, ::Node, etc.) def chef_object raise NotFoundError.new(self) if !exists? nil end # Create a child of this entry with the given name and contents. If # contents is nil, create a directory. # # NOTE: create_child_from is an optional method that can also be added to # your entry class, and will be called without actually reading the # file_contents. This is used for knife upload /cookbooks/cookbookname. def create_child(name, file_contents) raise NotFoundError.new(self) if !exists? raise OperationNotAllowedError.new(:create_child, self) end # Delete this item, possibly recursively. Entries MUST NOT delete a # directory unless recurse is true. def delete(recurse) raise NotFoundError.new(self) if !exists? raise OperationNotAllowedError.new(:delete, self) end # Ask whether this entry is a directory. If not, it is a file. def dir? false end # Ask whether this entry exists. def exists? true end # Printable path, generally used to distinguish paths in one root from # paths in another. def path_for_printing if parent parent_path = parent.path_for_printing if parent_path == '.' name else Chef::ChefFS::PathUtils::join(parent.path_for_printing, name) end else name end end def root parent ? parent.root : self end # Read the contents of this file entry. def read raise NotFoundError.new(self) if !exists? raise OperationNotAllowedError.new(:read, self) end # Write the contents of this file entry. def write(file_contents) raise NotFoundError.new(self) if !exists? raise OperationNotAllowedError.new(:write, self) end # Important directory attributes: name, parent, path, root # Overridable attributes: dir?, child(name), path_for_printing # Abstract: read, write, delete, children, can_have_child?, create_child, compare_to end # class BaseFsObject end end end require 'chef/chef_fs/file_system/nonexistent_fs_object' chef-11.8.2/lib/chef/chef_fs/file_system/memory_dir.rb0000644000004100000410000000260312254362222022627 0ustar www-datawww-datarequire 'chef/chef_fs/file_system/base_fs_dir' require 'chef/chef_fs/file_system/nonexistent_fs_object' require 'chef/chef_fs/file_system/memory_file' class Chef module ChefFS module FileSystem class MemoryDir < Chef::ChefFS::FileSystem::BaseFSDir def initialize(name, parent) super(name, parent) @children = [] end attr_reader :children def child(name) @children.select { |child| child.name == name }.first || Chef::ChefFS::FileSystem::NonexistentFSObject.new(name, self) end def add_child(child) @children.push(child) end def can_have_child?(name, is_dir) root.cannot_be_in_regex ? (name !~ root.cannot_be_in_regex) : true end def add_file(path, value) path_parts = path.split('/') dir = add_dir(path_parts[0..-2].join('/')) file = MemoryFile.new(path_parts[-1], dir, value) dir.add_child(file) file end def add_dir(path) path_parts = path.split('/') dir = self path_parts.each do |path_part| subdir = dir.child(path_part) if !subdir.exists? subdir = MemoryDir.new(path_part, dir) dir.add_child(subdir) end dir = subdir end dir end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb0000644000004100000410000001075112254362222030174 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/base_fs_dir' require 'chef/chef_fs/file_system/chef_repository_file_system_entry' require 'chef/chef_fs/file_system/chef_repository_file_system_acls_dir' require 'chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir' require 'chef/chef_fs/file_system/chef_repository_file_system_data_bags_dir' require 'chef/chef_fs/file_system/multiplexed_dir' require 'chef/chef_fs/data_handler/client_data_handler' require 'chef/chef_fs/data_handler/environment_data_handler' require 'chef/chef_fs/data_handler/node_data_handler' require 'chef/chef_fs/data_handler/role_data_handler' require 'chef/chef_fs/data_handler/user_data_handler' require 'chef/chef_fs/data_handler/group_data_handler' require 'chef/chef_fs/data_handler/container_data_handler' class Chef module ChefFS module FileSystem class ChefRepositoryFileSystemRootDir < BaseFSDir def initialize(child_paths) super("", nil) @child_paths = child_paths end attr_accessor :write_pretty_json attr_reader :child_paths def children @children ||= child_paths.keys.sort.map { |name| make_child_entry(name) }.select { |child| !child.nil? } end def can_have_child?(name, is_dir) child_paths.has_key?(name) && is_dir end def create_child(name, file_contents = nil) child_paths[name].each do |path| begin Dir.mkdir(path) rescue Errno::EEXIST end end child = make_child_entry(name) @children = nil child end def json_class nil end # Used to print out the filesystem def fs_description repo_path = File.dirname(child_paths['cookbooks'][0]) result = "repository at #{repo_path}\n" if Chef::Config[:versioned_cookbooks] result << " Multiple versions per cookbook\n" else result << " One version per cookbook\n" end child_paths.each_pair do |name, paths| if paths.any? { |path| File.dirname(path) != repo_path } result << " #{name} at #{paths.join(', ')}\n" end end result end private def make_child_entry(name) paths = child_paths[name].select do |path| File.exists?(path) end if paths.size == 0 return nil end if name == 'cookbooks' dirs = paths.map { |path| ChefRepositoryFileSystemCookbooksDir.new(name, self, path) } elsif name == 'data_bags' dirs = paths.map { |path| ChefRepositoryFileSystemDataBagsDir.new(name, self, path) } elsif name == 'acls' dirs = paths.map { |path| ChefRepositoryFileSystemAclsDir.new(name, self, path) } else data_handler = case name when 'clients' Chef::ChefFS::DataHandler::ClientDataHandler.new when 'environments' Chef::ChefFS::DataHandler::EnvironmentDataHandler.new when 'nodes' Chef::ChefFS::DataHandler::NodeDataHandler.new when 'roles' Chef::ChefFS::DataHandler::RoleDataHandler.new when 'users' Chef::ChefFS::DataHandler::UserDataHandler.new when 'groups' Chef::ChefFS::DataHandler::GroupDataHandler.new when 'containers' Chef::ChefFS::DataHandler::ContainerDataHandler.new else raise "Unknown top level path #{name}" end dirs = paths.map { |path| ChefRepositoryFileSystemEntry.new(name, self, path, data_handler) } end MultiplexedDir.new(dirs) end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/already_exists_error.rb0000644000004100000410000000172612254362222024717 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/operation_failed_error' class Chef module ChefFS module FileSystem class AlreadyExistsError < OperationFailedError def initialize(operation, entry, cause = nil) super(operation, entry, cause) end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/multiplexed_dir.rb0000644000004100000410000000257312254362222023661 0ustar www-datawww-datarequire 'chef/chef_fs/file_system/base_fs_object' require 'chef/chef_fs/file_system/nonexistent_fs_object' class Chef module ChefFS module FileSystem class MultiplexedDir < BaseFSDir def initialize(*multiplexed_dirs) @multiplexed_dirs = multiplexed_dirs.flatten super(@multiplexed_dirs[0].name, @multiplexed_dirs[0].parent) end attr_reader :multiplexed_dirs def write_dir multiplexed_dirs[0] end def children begin result = [] seen = {} # If multiple things have the same name, the first one wins. multiplexed_dirs.each do |dir| dir.children.each do |child| if seen[child.name] Chef::Log.warn("Child with name '#{child.name}' found in multiple directories: #{seen[child.name].path_for_printing} and #{child.path_for_printing}") else result << child seen[child.name] = child end end end result end end def can_have_child?(name, is_dir) write_dir.can_have_child?(name, is_dir) end def create_child(name, file_contents = nil) @children = nil write_dir.create_child(name, file_contents) end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/not_found_error.rb0000644000004100000410000000166112254362222023670 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/file_system_error' class Chef module ChefFS module FileSystem class NotFoundError < FileSystemError def initialize(entry, cause = nil) super(entry, cause) end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir.rb0000644000004100000410000000712012254362222031013 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry' require 'chef/chef_fs/file_system/cookbook_dir' require 'chef/chef_fs/file_system/not_found_error' require 'chef/cookbook/chefignore' require 'chef/cookbook/cookbook_version_loader' class Chef module ChefFS module FileSystem class ChefRepositoryFileSystemCookbookDir < ChefRepositoryFileSystemCookbookEntry def initialize(name, parent, file_path = nil) super(name, parent, file_path) end def chef_object begin loader = Chef::Cookbook::CookbookVersionLoader.new(file_path, parent.chefignore) # We need the canonical cookbook name if we are using versioned cookbooks, but we don't # want to spend a lot of time adding code to the main Chef libraries if Chef::Config[:versioned_cookbooks] _canonical_name = canonical_cookbook_name(File.basename(file_path)) fail "When versioned_cookbooks mode is on, cookbook #{file_path} must match format -x.y.z" unless _canonical_name # KLUDGE: We shouldn't have to use instance_variable_set loader.instance_variable_set(:@cookbook_name, _canonical_name) end loader.load_cookbooks return loader.cookbook_version rescue Chef::Log.error("Could not read #{path_for_printing} into a Chef object: #{$!}") end nil end def children begin Dir.entries(file_path).sort. select { |child_name| can_have_child?(child_name, File.directory?(File.join(file_path, child_name))) }. map { |child_name| make_child(child_name) }. select { |entry| !(entry.dir? && entry.children.size == 0) } rescue Errno::ENOENT raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!) end end def can_have_child?(name, is_dir) if is_dir # Only the given directories will be uploaded. return CookbookDir::COOKBOOK_SEGMENT_INFO.keys.include?(name.to_sym) && name != 'root_files' end super(name, is_dir) end # Exposed as a class method so that it can be used elsewhere def self.canonical_cookbook_name(entry_name) name_match = Chef::ChefFS::FileSystem::CookbookDir::VALID_VERSIONED_COOKBOOK_NAME.match(entry_name) return nil if name_match.nil? return name_match[1] end def canonical_cookbook_name(entry_name) self.class.canonical_cookbook_name(entry_name) end protected def make_child(child_name) segment_info = CookbookDir::COOKBOOK_SEGMENT_INFO[child_name.to_sym] || {} ChefRepositoryFileSystemCookbookEntry.new(child_name, self, nil, segment_info[:ruby_only], segment_info[:recursive]) end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry.rb0000644000004100000410000000552412254362222031404 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/chef_repository_file_system_entry' require 'chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir' require 'chef/chef_fs/file_system/not_found_error' class Chef module ChefFS module FileSystem class ChefRepositoryFileSystemCookbookEntry < ChefRepositoryFileSystemEntry def initialize(name, parent, file_path = nil, ruby_only = false, recursive = false) super(name, parent, file_path) @ruby_only = ruby_only @recursive = recursive end attr_reader :ruby_only attr_reader :recursive def children begin Dir.entries(file_path).sort. select { |child_name| can_have_child?(child_name, File.directory?(File.join(file_path, child_name))) }. map { |child_name| make_child(child_name) }. select { |entry| !(entry.dir? && entry.children.size == 0) } rescue Errno::ENOENT raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!) end end def can_have_child?(name, is_dir) if is_dir return recursive && name != '.' && name != '..' elsif ruby_only return false if name[-3..-1] != '.rb' end # Check chefignore ignorer = parent begin if ignorer.is_a?(ChefRepositoryFileSystemCookbooksDir) # Grab the path from entry to child path_to_child = name child = self while child.parent != ignorer path_to_child = PathUtils.join(child.name, path_to_child) child = child.parent end # Check whether that relative path is ignored return !ignorer.chefignore || !ignorer.chefignore.ignored?(path_to_child) end ignorer = ignorer.parent end while ignorer true end def write_pretty_json false end protected def make_child(child_name) ChefRepositoryFileSystemCookbookEntry.new(child_name, self, nil, ruby_only, recursive) end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/cookbook_frozen_error.rb0000644000004100000410000000172312254362222025065 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/already_exists_error' class Chef module ChefFS module FileSystem class CookbookFrozenError < AlreadyExistsError def initialize(operation, entry, cause = nil) super(operation, entry, cause) end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/acls_dir.rb0000644000004100000410000000413112254362222022237 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/base_fs_dir' require 'chef/chef_fs/file_system/acl_dir' require 'chef/chef_fs/file_system/cookbooks_acl_dir' require 'chef/chef_fs/file_system/acl_entry' require 'chef/chef_fs/data_handler/acl_data_handler' class Chef module ChefFS module FileSystem class AclsDir < BaseFSDir ENTITY_TYPES = %w(clients containers cookbooks data_bags environments groups nodes roles) # we don't read sandboxes, so we don't read their acls def initialize(parent) super('acls', parent) end def data_handler @data_handler ||= Chef::ChefFS::DataHandler::AclDataHandler.new end def api_path parent.api_path end def can_have_child?(name, is_dir) is_dir ? ENTITY_TYPES.include(name) : name == 'organization.json' end def children if @children.nil? @children = ENTITY_TYPES.map do |entity_type| case entity_type when 'cookbooks' CookbooksAclDir.new(entity_type, self) else AclDir.new(entity_type, self) end end @children << AclEntry.new('organization.json', self, true) # the org acl is retrieved as GET /organizations/ORGNAME/ANYTHINGATALL/_acl end @children end def rest parent.rest end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/file_system_entry.rb0000644000004100000410000000531412254362222024227 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/base_fs_dir' require 'chef/chef_fs/file_system/rest_list_dir' require 'chef/chef_fs/file_system/not_found_error' require 'chef/chef_fs/file_system/must_delete_recursively_error' require 'chef/chef_fs/path_utils' require 'fileutils' class Chef module ChefFS module FileSystem class FileSystemEntry < BaseFSDir def initialize(name, parent, file_path = nil) super(name, parent) @file_path = file_path || "#{parent.file_path}/#{name}" end attr_reader :file_path def path_for_printing file_path end def children begin Dir.entries(file_path).sort.select { |entry| entry != '.' && entry != '..' }.map { |entry| make_child(entry) } rescue Errno::ENOENT raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!) end end def create_child(child_name, file_contents=nil) child = make_child(child_name) if file_contents child.write(file_contents) else begin Dir.mkdir(child.file_path) rescue Errno::EEXIST end end @children = nil child end def dir? File.directory?(file_path) end def delete(recurse) if dir? if !recurse raise MustDeleteRecursivelyError.new(self, $!) end FileUtils.rm_rf(file_path) else File.delete(file_path) end end def read begin File.open(file_path, "rb") {|f| f.read} rescue Errno::ENOENT raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!) end end def write(content) File.open(file_path, 'wb') do |file| file.write(content) end end protected def make_child(child_name) FileSystemEntry.new(child_name, self) end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/rest_list_entry.rb0000644000004100000410000001327212254362222023716 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/base_fs_object' require 'chef/chef_fs/file_system/not_found_error' require 'chef/chef_fs/file_system/operation_failed_error' require 'chef/role' require 'chef/node' class Chef module ChefFS module FileSystem class RestListEntry < BaseFSObject def initialize(name, parent, exists = nil) super(name, parent) @exists = exists end def data_handler parent.data_handler end def api_child_name if name.length < 5 || name[-5,5] != ".json" raise "Invalid name #{path}: must end in .json" end name[0,name.length-5] end def api_path "#{parent.api_path}/#{api_child_name}" end def org parent.org end def environment parent.environment end def exists? if @exists.nil? begin @exists = parent.children.any? { |child| child.name == name } rescue Chef::ChefFS::FileSystem::NotFoundError @exists = false end end @exists end def delete(recurse) begin rest.delete(api_path) rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}" rescue Net::HTTPServerException => e if e.response.code == "404" raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e) else raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}" end end end def read Chef::JSONCompat.to_json_pretty(_read_hash) end def _read_hash begin # Minimize the value (get rid of defaults) so the results don't look terrible minimize_value(root.get_json(api_path)) rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "Timeout reading: #{e}" rescue Net::HTTPServerException => e if $!.response.code == "404" raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e) else raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "HTTP error reading: #{e}" end end end def chef_object # REST will inflate the Chef object using json_class data_handler.json_class.json_create(read) end def minimize_value(value) data_handler.minimize(data_handler.normalize(value, self), self) end def compare_to(other) # TODO this pair of reads can be parallelized # Grab the other value begin other_value_json = other.read rescue Chef::ChefFS::FileSystem::NotFoundError return [ nil, nil, :none ] end # Grab this value begin value = _read_hash rescue Chef::ChefFS::FileSystem::NotFoundError return [ false, :none, other_value_json ] end # Minimize (and normalize) both values for easy and beautiful diffs value = minimize_value(value) value_json = Chef::JSONCompat.to_json_pretty(value) begin other_value = JSON.parse(other_value_json, :create_additions => false) rescue JSON::ParserError => e Chef::Log.warn("Parse error reading #{other.path_for_printing} as JSON: #{e}") return [ nil, value_json, other_value_json ] end other_value = minimize_value(other_value) other_value_json = Chef::JSONCompat.to_json_pretty(other_value) [ value == other_value, value_json, other_value_json ] end def rest parent.rest end def write(file_contents) begin object = JSON.parse(file_contents, :create_additions => false) rescue JSON::ParserError => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Parse error reading JSON: #{e}" end if data_handler object = data_handler.normalize_for_put(object, self) data_handler.verify_integrity(object, self) do |error| raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self), "#{error}" end end begin rest.put(api_path, object) rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Timeout writing: #{e}" rescue Net::HTTPServerException => e if e.response.code == "404" raise Chef::ChefFS::FileSystem::NotFoundError.new(self, e) else raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "HTTP error writing: #{e}" end end end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb0000644000004100000410000000553412254362222027517 0ustar www-datawww-data# # Author:: John Keiser () # Author:: Ho-Sheng Hsiao () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/file_system_entry' require 'chef/chef_fs/file_system/not_found_error' class Chef module ChefFS module FileSystem # ChefRepositoryFileSystemEntry works just like FileSystemEntry, # except can inflate Chef objects class ChefRepositoryFileSystemEntry < FileSystemEntry def initialize(name, parent, file_path = nil, data_handler = nil) super(name, parent, file_path) @data_handler = data_handler end def write_pretty_json root.write_pretty_json end def data_handler @data_handler || parent.data_handler end def chef_object begin return data_handler.chef_object(JSON.parse(read, :create_additions => false)) rescue Chef::Log.error("Could not read #{path_for_printing} into a Chef object: #{$!}") end nil end def can_have_child?(name, is_dir) !is_dir && name[-5..-1] == '.json' end def write(file_contents) if file_contents && write_pretty_json && name[-5..-1] == '.json' file_contents = minimize(file_contents, self) end super(file_contents) end def minimize(file_contents, entry) object = JSONCompat.from_json(file_contents, :create_additions => false) object = data_handler.normalize(object, entry) object = data_handler.minimize(object, entry) JSONCompat.to_json_pretty(object) end def children # Except cookbooks and data bag dirs, all things must be json files begin Dir.entries(file_path).sort. select { |child_name| can_have_child?(child_name, File.directory?(File.join(file_path, child_name))) }. map { |child_name| make_child(child_name) } rescue Errno::ENOENT raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!) end end protected def make_child(child_name) ChefRepositoryFileSystemEntry.new(child_name, self) end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/operation_not_allowed_error.rb0000644000004100000410000000253112254362222026261 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/file_system_error' class Chef module ChefFS module FileSystem class OperationNotAllowedError < FileSystemError def initialize(operation, entry, cause = nil) super(entry, cause) @operation = operation end attr_reader :operation attr_reader :entry def reason case operation when :delete "cannot be deleted" when :write "cannot be updated" when :create_child "cannot have a child created under it" when :read "cannot be read" end end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/cookbooks_acl_dir.rb0000644000004100000410000000302612254362222024127 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/acl_dir' require 'chef/chef_fs/file_system/acl_entry' class Chef module ChefFS module FileSystem class CookbooksAclDir < AclDir # If versioned_cookbooks is on, the list of cookbooks will have versions # in them. But all versions of a cookbook have the same acl, so even if # we have cookbooks/apache2-1.0.0 and cookbooks/apache2-1.1.2, we will # only have one acl: acls/cookbooks/apache2.json. Thus, the list of # children of acls/cookbooks is a unique list of cookbook *names*. def children if @children.nil? names = parent.parent.child(name).children.map { |child| "#{child.cookbook_name}.json" } @children = names.uniq.map { |name| AclEntry.new(name, self, true) } end @children end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/file_system_root_dir.rb0000644000004100000410000000166212254362222024711 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/file_system_entry' class Chef module ChefFS module FileSystem class FileSystemRootDir < FileSystemEntry def initialize(file_path) super("", nil, file_path) end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/must_delete_recursively_error.rb0000644000004100000410000000167612254362222026651 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/file_system_error' class Chef module ChefFS module FileSystem class MustDeleteRecursivelyError < FileSystemError def initialize(entry, cause = nil) super(entry, cause) end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/chef_repository_file_system_data_bags_dir.rb0000644000004100000410000000231112254362222031107 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/chef_repository_file_system_entry' require 'chef/chef_fs/data_handler/data_bag_item_data_handler' class Chef module ChefFS module FileSystem class ChefRepositoryFileSystemDataBagsDir < ChefRepositoryFileSystemEntry def initialize(name, parent, path = nil) super(name, parent, path, Chef::ChefFS::DataHandler::DataBagItemDataHandler.new) end def can_have_child?(name, is_dir) is_dir && !name.start_with?('.') end end end end end chef-11.8.2/lib/chef/chef_fs/file_system/cookbooks_dir.rb0000644000004100000410000001441712254362222023316 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/chef_fs/file_system/rest_list_dir' require 'chef/chef_fs/file_system/cookbook_dir' require 'chef/chef_fs/file_system/operation_failed_error' require 'chef/chef_fs/file_system/cookbook_frozen_error' require 'chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir' require 'chef/mixin/file_class' require 'tmpdir' class Chef module ChefFS module FileSystem class CookbooksDir < RestListDir include Chef::Mixin::FileClass def initialize(parent) super("cookbooks", parent) end def child(name) if @children result = self.children.select { |child| child.name == name }.first if result result else NonexistentFSObject.new(name, self) end else CookbookDir.new(name, self) end end def children @children ||= begin if Chef::Config[:versioned_cookbooks] result = [] root.get_json("#{api_path}/?num_versions=all").each_pair do |cookbook_name, cookbooks| cookbooks['versions'].each do |cookbook_version| result << CookbookDir.new("#{cookbook_name}-#{cookbook_version['version']}", self, :exists => true) end end else result = root.get_json(api_path).keys.map { |cookbook_name| CookbookDir.new(cookbook_name, self, :exists => true) } end result.sort_by(&:name) end end def create_child_from(other, options = {}) @children = nil upload_cookbook_from(other, options) end def upload_cookbook_from(other, options = {}) Chef::Config[:versioned_cookbooks] ? upload_versioned_cookbook(other, options) : upload_unversioned_cookbook(other, options) rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Timeout writing: #{e}" rescue Net::HTTPServerException => e case e.response.code when "409" raise Chef::ChefFS::FileSystem::CookbookFrozenError.new(:write, self, e), "Cookbook #{other.name} is frozen" else raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "HTTP error writing: #{e}" end rescue Chef::Exceptions::CookbookFrozen => e raise Chef::ChefFS::FileSystem::CookbookFrozenError.new(:write, self, e), "Cookbook #{other.name} is frozen" end # Knife currently does not understand versioned cookbooks # Cookbook Version uploader also requires a lot of refactoring # to make this work. So instead, we make a temporary cookbook # symlinking back to real cookbook, and upload the proxy. def upload_versioned_cookbook(other, options) cookbook_name = Chef::ChefFS::FileSystem::ChefRepositoryFileSystemCookbookDir.canonical_cookbook_name(other.name) Dir.mktmpdir do |temp_cookbooks_path| proxy_cookbook_path = "#{temp_cookbooks_path}/#{cookbook_name}" # Make a symlink file_class.symlink other.file_path, proxy_cookbook_path # Instantiate a proxy loader using the temporary symlink proxy_loader = Chef::Cookbook::CookbookVersionLoader.new(proxy_cookbook_path, other.parent.chefignore) proxy_loader.load_cookbooks cookbook_to_upload = proxy_loader.cookbook_version cookbook_to_upload.freeze_version if options[:freeze] # Instantiate a new uploader based on the proxy loader uploader = Chef::CookbookUploader.new(cookbook_to_upload, proxy_cookbook_path, :force => options[:force], :rest => root.chef_rest) with_actual_cookbooks_dir(temp_cookbooks_path) do upload_cookbook!(uploader) end # # When the temporary directory is being deleted on # windows, the contents of the symlink under that # directory is also deleted. So explicitly remove # the symlink without removing the original contents if we # are running on windows # if Chef::Platform.windows? Dir.rmdir proxy_cookbook_path end end end def upload_unversioned_cookbook(other, options) cookbook_to_upload = other.chef_object cookbook_to_upload.freeze_version if options[:freeze] uploader = Chef::CookbookUploader.new(cookbook_to_upload, other.parent.file_path, :force => options[:force], :rest => root.chef_rest) with_actual_cookbooks_dir(other.parent.file_path) do upload_cookbook!(uploader) end end # Work around the fact that CookbookUploader doesn't understand chef_repo_path (yet) def with_actual_cookbooks_dir(actual_cookbook_path) old_cookbook_path = Chef::Config.cookbook_path Chef::Config.cookbook_path = actual_cookbook_path if !Chef::Config.cookbook_path yield ensure Chef::Config.cookbook_path = old_cookbook_path end def upload_cookbook!(uploader, options = {}) if uploader.respond_to?(:upload_cookbook) uploader.upload_cookbook else uploader.upload_cookbooks end end def can_have_child?(name, is_dir) return false if !is_dir return false if Chef::Config[:versioned_cookbooks] && name !~ Chef::ChefFS::FileSystem::CookbookDir::VALID_VERSIONED_COOKBOOK_NAME return true end end end end end chef-11.8.2/lib/chef/chef_fs/chef_fs_data_store.rb0000644000004100000410000002777212254362222021756 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef_zero/data_store/memory_store' require 'chef_zero/data_store/data_already_exists_error' require 'chef_zero/data_store/data_not_found_error' require 'chef/chef_fs/file_pattern' require 'chef/chef_fs/file_system' require 'chef/chef_fs/file_system/not_found_error' require 'chef/chef_fs/file_system/memory_root' class Chef module ChefFS class ChefFSDataStore def initialize(chef_fs) @chef_fs = chef_fs @memory_store = ChefZero::DataStore::MemoryStore.new end def publish_description "Reading and writing data to #{chef_fs.fs_description}" end attr_reader :chef_fs def create_dir(path, name, *options) if use_memory_store?(path) @memory_store.create_dir(path, name, *options) else with_dir(path) do |parent| parent.create_child(chef_fs_filename(path + [name]), nil) end end end def create(path, name, data, *options) if use_memory_store?(path) @memory_store.create(path, name, data, *options) elsif path[0] == 'cookbooks' && path.length == 2 # Do nothing. The entry gets created when the cookbook is created. else if !data.is_a?(String) raise "set only works with strings" end with_dir(path) do |parent| parent.create_child(chef_fs_filename(path + [name]), data) end end end def get(path, request=nil) if use_memory_store?(path) @memory_store.get(path) elsif path[0] == 'file_store' && path[1] == 'repo' entry = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path[2..-1].join('/')) begin entry.read rescue Chef::ChefFS::FileSystem::NotFoundError => e raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e) end else with_entry(path) do |entry| if path[0] == 'cookbooks' && path.length == 3 # get /cookbooks/NAME/version result = entry.chef_object.to_hash result.each_pair do |key, value| if value.is_a?(Array) value.each do |file| if file.is_a?(Hash) && file.has_key?('checksum') relative = ['file_store', 'repo', 'cookbooks'] if Chef::Config.versioned_cookbooks relative << "#{path[1]}-#{path[2]}" else relative << path[1] end relative = relative + file[:path].split('/') file['url'] = ChefZero::RestBase::build_uri(request.base_uri, relative) end end end end JSON.pretty_generate(result) else entry.read end end end end def set(path, data, *options) if use_memory_store?(path) @memory_store.set(path, data, *options) else if !data.is_a?(String) raise "set only works with strings: #{path} = #{data.inspect}" end # Write out the files! if path[0] == 'cookbooks' && path.length == 3 write_cookbook(path, data, *options) else with_dir(path[0..-2]) do |parent| parent.create_child(chef_fs_filename(path), data) end end end end def delete(path) if use_memory_store?(path) @memory_store.delete(path) else with_entry(path) do |entry| if path[0] == 'cookbooks' && path.length >= 3 entry.delete(true) else entry.delete(false) end end end end def delete_dir(path, *options) if use_memory_store?(path) @memory_store.delete_dir(path, *options) else with_entry(path) do |entry| entry.delete(options.include?(:recursive)) end end end def list(path) if use_memory_store?(path) @memory_store.list(path) elsif path[0] == 'cookbooks' && path.length == 1 with_entry(path) do |entry| begin if Chef::Config.versioned_cookbooks # /cookbooks/name-version -> /cookbooks/name entry.children.map { |child| split_name_version(child.name)[0] }.uniq else entry.children.map { |child| child.name } end rescue Chef::ChefFS::FileSystem::NotFoundError # If the cookbooks dir doesn't exist, we have no cookbooks (not 404) [] end end elsif path[0] == 'cookbooks' && path.length == 2 if Chef::Config.versioned_cookbooks # list /cookbooks/name = filter /cookbooks/name-version down to name entry.children.map { |child| split_name_version(child.name) }. select { |name, version| name == path[1] }. map { |name, version| version }.to_a else # list /cookbooks/name = version = get_single_cookbook_version(path) [version] end else with_entry(path) do |entry| begin entry.children.map { |c| zero_filename(c) }.sort rescue Chef::ChefFS::FileSystem::NotFoundError # /cookbooks, /data, etc. never return 404 if path_always_exists?(path) [] else raise end end end end end def exists?(path) if use_memory_store?(path) @memory_store.exists?(path) else path_always_exists?(path) || Chef::ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path)).exists? end end def exists_dir?(path) if use_memory_store?(path) @memory_store.exists_dir?(path) elsif path[0] == 'cookbooks' && path.length == 2 list([ path[0] ]).include?(path[1]) else Chef::ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path)).exists? end end private def use_memory_store?(path) return path[0] == 'sandboxes' || path[0] == 'file_store' && path[1] == 'checksums' || path == [ 'environments', '_default' ] end def write_cookbook(path, data, *options) # Create a little Chef::ChefFS memory filesystem with the data if Chef::Config.versioned_cookbooks cookbook_path = "cookbooks/#{path[1]}-#{path[2]}" else cookbook_path = "cookbooks/#{path[1]}" end cookbook_fs = Chef::ChefFS::FileSystem::MemoryRoot.new('uploading') cookbook = JSON.parse(data, :create_additions => false) cookbook.each_pair do |key, value| if value.is_a?(Array) value.each do |file| if file.is_a?(Hash) && file.has_key?('checksum') file_data = @memory_store.get(['file_store', 'checksums', file['checksum']]) cookbook_fs.add_file("#{cookbook_path}/#{file['path']}", file_data) end end end end # Use the copy/diff algorithm to copy it down so we don't destroy # chefignored data. This is terribly un-thread-safe. Chef::ChefFS::FileSystem.copy_to(Chef::ChefFS::FilePattern.new("/#{cookbook_path}"), cookbook_fs, chef_fs, nil, {:purge => true}) end def split_name_version(entry_name) name_version = entry_name.split('-') name = name_version[0..-2].join('-') version = name_version[-1] [name,version] end def to_chef_fs_path(path) _to_chef_fs_path(path).join('/') end def chef_fs_filename(path) _to_chef_fs_path(path)[-1] end def _to_chef_fs_path(path) if path[0] == 'data' path = path.dup path[0] = 'data_bags' if path.length >= 3 path[2] = "#{path[2]}.json" end elsif path[0] == 'cookbooks' if path.length == 2 raise ChefZero::DataStore::DataNotFoundError.new(path) elsif Chef::Config.versioned_cookbooks if path.length >= 3 # cookbooks/name/version -> cookbooks/name-version path = [ path[0], "#{path[1]}-#{path[2]}" ] + path[3..-1] end else if path.length >= 3 # cookbooks/name/version/... -> /cookbooks/name/... iff metadata says so version = get_single_cookbook_version(path) if path[2] == version path = path[0..1] + path[3..-1] else raise ChefZero::DataStore::DataNotFoundError.new(path) end end end elsif path.length == 2 path = path.dup path[1] = "#{path[1]}.json" end path end def to_zero_path(entry) path = entry.path.split('/')[1..-1] if path[0] == 'data_bags' path = path.dup path[0] = 'data' if path.length >= 3 path[2] = path[2][0..-6] end elsif path[0] == 'cookbooks' if Chef::Config.versioned_cookbooks # cookbooks/name-version/... -> cookbooks/name/version/... if path.length >= 2 name, version = split_name_version(path[1]) path = [ path[0], name, version ] + path[2..-1] end else if path.length >= 2 # cookbooks/name/... -> cookbooks/name/version/... version = get_single_cookbook_version(path) path = path[0..1] + [version] + path[2..-1] end end elsif path.length == 2 && path[0] != 'cookbooks' path = path.dup path[1] = path[1][0..-6] end path end def zero_filename(entry) to_zero_path(entry)[-1] end def path_always_exists?(path) return path.length == 1 && %w(clients cookbooks data environments nodes roles users).include?(path[0]) end def with_entry(path) begin yield Chef::ChefFS::FileSystem.resolve_path(chef_fs, to_chef_fs_path(path)) rescue Chef::ChefFS::FileSystem::NotFoundError => e raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e) end end def with_dir(path) begin yield get_dir(_to_chef_fs_path(path), true) rescue Chef::ChefFS::FileSystem::NotFoundError => e raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e) end end def get_dir(path, create=false) result = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path.join('/')) if result.exists? result elsif create get_dir(path[0..-2], create).create_child(result.name, nil) else raise ChefZero::DataStore::DataNotFoundError.new(path) end end def get_single_cookbook_version(path) dir = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path[0..1].join('/')) metadata = ChefZero::CookbookData.metadata_from(dir, path[1], nil, []) metadata[:version] || '0.0.0' end end end end chef-11.8.2/lib/chef/chef_fs/parallelizer.rb0000644000004100000410000000654612254362222020636 0ustar www-datawww-dataclass Chef module ChefFS class Parallelizer @@parallelizer = nil @@threads = 0 def self.threads=(value) if @@threads != value @@threads = value @@parallelizer = nil end end def self.parallelize(enumerator, options = {}, &block) @@parallelizer ||= Parallelizer.new(@@threads) @@parallelizer.parallelize(enumerator, options, &block) end def initialize(threads) @tasks_mutex = Mutex.new @tasks = [] @threads = [] 1.upto(threads) do @threads << Thread.new { worker_loop } end end def parallelize(enumerator, options = {}, &block) task = ParallelizedResults.new(enumerator, options, &block) @tasks_mutex.synchronize do @tasks << task end task end class ParallelizedResults include Enumerable def initialize(enumerator, options, &block) @inputs = enumerator.to_a @options = options @block = block @mutex = Mutex.new @outputs = [] @status = [] end def each next_index = 0 while true # Report any results that already exist while @status.length > next_index && ([:finished, :exception].include?(@status[next_index])) if @status[next_index] == :finished if @options[:flatten] @outputs[next_index].each do |entry| yield entry end else yield @outputs[next_index] end else raise @outputs[next_index] end next_index = next_index + 1 end # Pick up a result and process it, if there is one. This ensures we # move forward even if there are *zero* worker threads available. if !process_input # Exit if we're done. if next_index >= @status.length break else # Ruby 1.8 threading sucks. Wait till we process more things. sleep(0.05) end end end end def process_input # Grab the next one to process index, input = @mutex.synchronize do index = @status.length if index >= @inputs.length return nil end input = @inputs[index] @status[index] = :started [ index, input ] end begin @outputs[index] = @block.call(input) @status[index] = :finished rescue Exception @outputs[index] = $! @status[index] = :exception end index end end private def worker_loop while true begin task = @tasks[0] if task if !task.process_input @tasks_mutex.synchronize do @tasks.delete(task) end end else # Ruby 1.8 threading sucks. Wait a bit to see if another task comes in. sleep(0.05) end rescue puts "ERROR #{$!}" puts $!.backtrace end end end end end end chef-11.8.2/lib/chef/chef_fs/data_handler/0000755000004100000410000000000012254362222020216 5ustar www-datawww-datachef-11.8.2/lib/chef/chef_fs/data_handler/client_data_handler.rb0000644000004100000410000000167712254362222024522 0ustar www-datawww-datarequire 'chef/chef_fs/data_handler/data_handler_base' require 'chef/api_client' class Chef module ChefFS module DataHandler class ClientDataHandler < DataHandlerBase def normalize(client, entry) defaults = { 'name' => remove_dot_json(entry.name), 'clientname' => remove_dot_json(entry.name), 'admin' => false, 'validator' => false, 'chef_type' => 'client' } if entry.respond_to?(:org) && entry.org defaults['orgname'] = entry.org end result = normalize_hash(client, defaults) # You can NOT send json_class, or it will fail result.delete('json_class') result end def preserve_key(key) return key == 'name' end def chef_class Chef::ApiClient end # There is no Ruby API for Chef::ApiClient end end end end chef-11.8.2/lib/chef/chef_fs/data_handler/acl_data_handler.rb0000644000004100000410000000137412254362222023775 0ustar www-datawww-datarequire 'chef/chef_fs/data_handler/data_handler_base' class Chef module ChefFS module DataHandler class AclDataHandler < DataHandlerBase def normalize(node, entry) # Normalize the order of the keys for easier reading result = normalize_hash(node, { 'create' => {}, 'read' => {}, 'update' => {}, 'delete' => {}, 'grant' => {} }) result.keys.each do |key| result[key] = normalize_hash(result[key], { 'actors' => [], 'groups' => [] }) result[key]['actors'] = result[key]['actors'].sort result[key]['groups'] = result[key]['groups'].sort end result end end end end end chef-11.8.2/lib/chef/chef_fs/data_handler/data_handler_base.rb0000644000004100000410000000662112254362222024150 0ustar www-datawww-dataclass Chef module ChefFS module DataHandler class DataHandlerBase def minimize(object, entry) default_object = default(entry) object.each_pair do |key, value| if default_object[key] == value && !preserve_key(key) object.delete(key) end end object end def remove_dot_json(name) if name.length < 5 || name[-5,5] != ".json" raise "Invalid name #{path}: must end in .json" end name[0,name.length-5] end def preserve_key(key) false end def default(entry) normalize({}, entry) end def normalize_hash(object, defaults) # Make a normalized result in the specified order for diffing result = {} defaults.each_pair do |key, default| result[key] = object.has_key?(key) ? object[key] : default end object.each_pair do |key, value| result[key] = value if !result.has_key?(key) end result end def normalize_for_post(object, entry) normalize(object, entry) end def normalize_for_put(object, entry) normalize(object, entry) end def normalize_run_list(run_list) run_list.map{|item| case item.to_s when /^recipe\[.*\]$/ item # explicit recipe when /^role\[.*\]$/ item # explicit role else "recipe[#{item}]" end }.uniq end def from_ruby(ruby) chef_class.from_file(ruby).to_hash end def chef_object(object) chef_class.json_create(object) end def to_ruby(object) raise NotImplementedError end def chef_class raise NotImplementedError end def to_ruby_keys(object, keys) result = '' keys.each do |key| if object[key] if object[key].is_a?(Hash) if object[key].size > 0 result << key first = true object[key].each_pair do |k,v| if first first = false else result << ' '*key.length end result << " #{k.inspect} => #{v.inspect}\n" end end elsif object[key].is_a?(Array) if object[key].size > 0 result << key first = true object[key].each do |value| if first first = false else result << ", " end result << value.inspect end result << "\n" end elsif !object[key].nil? result << "#{key} #{object[key].inspect}\n" end end end result end def verify_integrity(object, entry, &on_error) base_name = remove_dot_json(entry.name) if object['name'] != base_name on_error.call("Name must be '#{base_name}' (is '#{object['name']}')") end end end # class DataHandlerBase end end end chef-11.8.2/lib/chef/chef_fs/data_handler/cookbook_data_handler.rb0000644000004100000410000000203612254362222025040 0ustar www-datawww-datarequire 'chef/chef_fs/data_handler/data_handler_base' require 'chef/cookbook/metadata' class Chef module ChefFS module DataHandler class CookbookDataHandler < DataHandlerBase def normalize(cookbook, entry) version = entry.name name = entry.parent.name result = normalize_hash(cookbook, { 'name' => "#{name}-#{version}", 'version' => version, 'cookbook_name' => name, 'json_class' => 'Chef::CookbookVersion', 'chef_type' => 'cookbook_version', 'frozen?' => false, 'metadata' => {} }) result['metadata'] = normalize_hash(result['metadata'], { 'version' => version, 'name' => name }) end def preserve_key(key) return key == 'cookbook_name' || key == 'version' end def chef_class Chef::Cookbook::Metadata end # Not using this yet, so not sure if to_ruby will be useful. end end end end chef-11.8.2/lib/chef/chef_fs/data_handler/role_data_handler.rb0000644000004100000410000000215212254362222024172 0ustar www-datawww-datarequire 'chef/chef_fs/data_handler/data_handler_base' require 'chef/role' class Chef module ChefFS module DataHandler class RoleDataHandler < DataHandlerBase def normalize(role, entry) result = normalize_hash(role, { 'name' => remove_dot_json(entry.name), 'description' => '', 'json_class' => 'Chef::Role', 'chef_type' => 'role', 'default_attributes' => {}, 'override_attributes' => {}, 'run_list' => [], 'env_run_lists' => {} }) result['run_list'] = normalize_run_list(result['run_list']) result['env_run_lists'].each_pair do |env, run_list| result['env_run_lists'][env] = normalize_run_list(run_list) end result end def preserve_key(key) return key == 'name' end def chef_class Chef::Role end def to_ruby(object) to_ruby_keys(object, %w(name description default_attributes override_attributes run_list env_run_lists)) end end end end end chef-11.8.2/lib/chef/chef_fs/data_handler/environment_data_handler.rb0000644000004100000410000000214212254362222025574 0ustar www-datawww-datarequire 'chef/chef_fs/data_handler/data_handler_base' require 'chef/environment' class Chef module ChefFS module DataHandler class EnvironmentDataHandler < DataHandlerBase def normalize(environment, entry) normalize_hash(environment, { 'name' => remove_dot_json(entry.name), 'description' => '', 'cookbook_versions' => {}, 'default_attributes' => {}, 'override_attributes' => {}, 'json_class' => 'Chef::Environment', 'chef_type' => 'environment' }) end def preserve_key(key) return key == 'name' end def chef_class Chef::Environment end def to_ruby(object) result = to_ruby_keys(object, %w(name description default_attributes override_attributes)) if object['cookbook_versions'] object['cookbook_versions'].each_pair do |name, version| result << "cookbook #{name.inspect}, #{version.inspect}" end end result end end end end end chef-11.8.2/lib/chef/chef_fs/data_handler/node_data_handler.rb0000644000004100000410000000156212254362222024162 0ustar www-datawww-datarequire 'chef/chef_fs/data_handler/data_handler_base' require 'chef/node' class Chef module ChefFS module DataHandler class NodeDataHandler < DataHandlerBase def normalize(node, entry) result = normalize_hash(node, { 'name' => remove_dot_json(entry.name), 'json_class' => 'Chef::Node', 'chef_type' => 'node', 'chef_environment' => '_default', 'override' => {}, 'normal' => {}, 'default' => {}, 'automatic' => {}, 'run_list' => [] }) result['run_list'] = normalize_run_list(result['run_list']) result end def preserve_key(key) return key == 'name' end def chef_class Chef::Node end # Nodes do not support .rb files end end end end chef-11.8.2/lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb0000644000004100000410000000354112254362222025774 0ustar www-datawww-datarequire 'chef/chef_fs/data_handler/data_handler_base' require 'chef/data_bag_item' class Chef module ChefFS module DataHandler class DataBagItemDataHandler < DataHandlerBase def normalize(data_bag_item, entry) # If it's wrapped with raw_data, unwrap it. if data_bag_item['json_class'] == 'Chef::DataBagItem' && data_bag_item['raw_data'] data_bag_item = data_bag_item['raw_data'] end # chef_type and data_bag come back in PUT and POST results, but we don't # use those in knife-essentials. normalize_hash(data_bag_item, { 'id' => remove_dot_json(entry.name) }) end def normalize_for_post(data_bag_item, entry) if data_bag_item['json_class'] == 'Chef::DataBagItem' && data_bag_item['raw_data'] data_bag_item = data_bag_item['raw_data'] end { "name" => "data_bag_item_#{entry.parent.name}_#{remove_dot_json(entry.name)}", "json_class" => "Chef::DataBagItem", "chef_type" => "data_bag_item", "data_bag" => entry.parent.name, "raw_data" => normalize(data_bag_item, entry) } end def normalize_for_put(data_bag_item, entry) normalize_for_post(data_bag_item, entry) end def preserve_key(key) return key == 'id' end def chef_class Chef::DataBagItem end def verify_integrity(object, entry, &on_error) base_name = remove_dot_json(entry.name) if object['raw_data']['id'] != base_name on_error.call("ID in #{entry.path_for_printing} must be '#{base_name}' (is '#{object['raw_data']['id']}')") end end # Data bags do not support .rb files (or if they do, it's undocumented) end end end end chef-11.8.2/lib/chef/chef_fs/data_handler/user_data_handler.rb0000644000004100000410000000123512254362222024210 0ustar www-datawww-datarequire 'chef/chef_fs/data_handler/data_handler_base' class Chef module ChefFS module DataHandler class UserDataHandler < DataHandlerBase def normalize(user, entry) normalize_hash(user, { 'name' => remove_dot_json(entry.name), 'admin' => false, 'json_class' => 'Chef::WebUIUser', 'chef_type' => 'webui_user', 'salt' => nil, 'password' => nil, 'openid' => nil }) end def preserve_key(key) return key == 'name' end # There is no chef_class for users, nor does to_ruby work. end end end end chef-11.8.2/lib/chef/chef_fs/data_handler/group_data_handler.rb0000644000004100000410000000252112254362222024365 0ustar www-datawww-datarequire 'chef/chef_fs/data_handler/data_handler_base' require 'chef/api_client' class Chef module ChefFS module DataHandler class GroupDataHandler < DataHandlerBase def normalize(group, entry) defaults = { 'name' => remove_dot_json(entry.name), 'groupname' => remove_dot_json(entry.name), 'users' => [], 'clients' => [], 'groups' => [], } if entry.org defaults['orgname'] = entry.org end result = normalize_hash(group, defaults) if result['actors'] && result['actors'].sort.uniq == (result['users'] + result['clients']).sort.uniq result.delete('actors') end result end def normalize_for_put(group, entry) result = super(group, entry) result['actors'] = { 'users' => result['users'], 'clients' => result['clients'], 'groups' => result['groups'] } result.delete('users') result.delete('clients') result.delete('groups') result end def preserve_key(key) return key == 'name' end def chef_class Chef::ApiClient end # There is no Ruby API for Chef::ApiClient end end end end chef-11.8.2/lib/chef/chef_fs/data_handler/container_data_handler.rb0000644000004100000410000000152312254362222025214 0ustar www-datawww-datarequire 'chef/chef_fs/data_handler/data_handler_base' class Chef module ChefFS module DataHandler class ContainerDataHandler < DataHandlerBase def normalize(container, entry) normalize_hash(container, { 'containername' => remove_dot_json(entry.name), 'containerpath' => remove_dot_json(entry.name) }) end def preserve_key(key) return key == 'containername' end def verify_integrity(object, entry, &on_error) base_name = remove_dot_json(entry.name) if object['containername'] != base_name on_error.call("Name in #{entry.path_for_printing} must be '#{base_name}' (is '#{object['name']}')") end end # There is no chef_class for users, nor does to_ruby work. end end end end chef-11.8.2/lib/chef/data_bag_item.rb0000644000004100000410000001260712254362222017306 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Nuo Yan () # Author:: Christopher Brown () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'forwardable' require 'chef/config' require 'chef/mixin/params_validate' require 'chef/mixin/from_file' require 'chef/data_bag' require 'chef/mash' require 'chef/json_compat' class Chef class DataBagItem extend Forwardable include Chef::Mixin::FromFile include Chef::Mixin::ParamsValidate VALID_ID = /^[\-[:alnum:]_]+$/ def self.validate_id!(id_str) if id_str.nil? || ( id_str !~ VALID_ID ) raise Exceptions::InvalidDataBagItemID, "Data Bag items must have an id matching #{VALID_ID.inspect}, you gave: #{id_str.inspect}" end end # Define all Hash's instance methods as delegating to @raw_data def_delegators(:@raw_data, *(Hash.instance_methods - Object.instance_methods)) attr_reader :raw_data # Create a new Chef::DataBagItem def initialize @data_bag = nil @raw_data = Mash.new end def chef_server_rest Chef::REST.new(Chef::Config[:chef_server_url]) end def self.chef_server_rest Chef::REST.new(Chef::Config[:chef_server_url]) end def raw_data @raw_data end def validate_id!(id_str) self.class.validate_id!(id_str) end def raw_data=(new_data) unless new_data.respond_to?(:[]) && new_data.respond_to?(:keys) raise Exceptions::ValidationFailed, "Data Bag Items must contain a Hash or Mash!" end validate_id!(new_data["id"]) @raw_data = new_data end def data_bag(arg=nil) set_or_return( :data_bag, arg, :regex => /^[\-[:alnum:]_]+$/ ) end def name object_name end def object_name raise Exceptions::ValidationFailed, "You must have an 'id' or :id key in the raw data" unless raw_data.has_key?('id') raise Exceptions::ValidationFailed, "You must have declared what bag this item belongs to!" unless data_bag id = raw_data['id'] "data_bag_item_#{data_bag}_#{id}" end def self.object_name(data_bag_name, id) "data_bag_item_#{data_bag_name}_#{id}" end def to_hash result = self.raw_data result["chef_type"] = "data_bag_item" result["data_bag"] = self.data_bag result end # Serialize this object as a hash def to_json(*a) result = { "name" => self.object_name, "json_class" => self.class.name, "chef_type" => "data_bag_item", "data_bag" => self.data_bag, "raw_data" => self.raw_data } result.to_json(*a) end def self.from_hash(h) item = new item.raw_data = h item end # Create a Chef::DataBagItem from JSON def self.json_create(o) bag_item = new bag_item.data_bag(o["data_bag"]) o.delete("data_bag") o.delete("chef_type") o.delete("json_class") o.delete("name") bag_item.raw_data = Mash.new(o["raw_data"]) bag_item end # Load a Data Bag Item by name via either the RESTful API or local data_bag_path if run in solo mode def self.load(data_bag, name) if Chef::Config[:solo] bag = Chef::DataBag.load(data_bag) item = bag[name] else item = Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("data/#{data_bag}/#{name}") end if item.kind_of?(DataBagItem) item else item = from_hash(item) item.data_bag(data_bag) item end end def destroy(data_bag=data_bag, databag_item=name) chef_server_rest.delete_rest("data/#{data_bag}/#{databag_item}") end # Save this Data Bag Item via RESTful API def save(item_id=@raw_data['id']) r = chef_server_rest begin if Chef::Config[:why_run] Chef::Log.warn("In whyrun mode, so NOT performing data bag item save.") else r.put_rest("data/#{data_bag}/#{item_id}", self) end rescue Net::HTTPServerException => e raise e unless e.response.code == "404" r.post_rest("data/#{data_bag}", self) end self end # Create this Data Bag Item via RESTful API def create chef_server_rest.post_rest("data/#{data_bag}", self) self end def ==(other) other.respond_to?(:to_hash) && other.respond_to?(:data_bag) && (other.to_hash == to_hash) && (other.data_bag.to_s == data_bag.to_s) end # As a string def to_s "data_bag_item[#{id}]" end def inspect "data_bag_item[#{data_bag.inspect}, #{raw_data['id'].inspect}, #{raw_data.inspect}]" end def pretty_print(pretty_printer) pretty_printer.pp({"data_bag_item('#{data_bag}', '#{id}')" => self.to_hash}) end def id @raw_data['id'] end end end chef-11.8.2/lib/chef/server_api.rb0000644000004100000410000000244312254362222016702 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/http' require 'chef/http/authenticator' require 'chef/http/cookie_manager' require 'chef/http/decompressor' require 'chef/http/json_input' require 'chef/http/json_output' class Chef class ServerAPI < Chef::HTTP def initialize(url = Chef::Config[:chef_server_url], options = {}) options[:client_name] ||= Chef::Config[:node_name] options[:signing_key_filename] ||= Chef::Config[:client_key] super(url, options) end use Chef::HTTP::JSONInput use Chef::HTTP::JSONOutput use Chef::HTTP::CookieManager use Chef::HTTP::Decompressor use Chef::HTTP::Authenticator end endchef-11.8.2/lib/chef/api_client.rb0000644000004100000410000001340712254362222016654 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Nuo Yan () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/config' require 'chef/mixin/params_validate' require 'chef/mixin/from_file' require 'chef/mash' require 'chef/json_compat' require 'chef/search/query' class Chef class ApiClient include Chef::Mixin::FromFile include Chef::Mixin::ParamsValidate # Create a new Chef::ApiClient object. def initialize @name = '' @public_key = nil @private_key = nil @admin = false @validator = false end # Gets or sets the client name. # # @params [Optional String] The name must be alpha-numeric plus - and _. # @return [String] The current value of the name. def name(arg=nil) set_or_return( :name, arg, :regex => /^[\-[:alnum:]_\.]+$/ ) end # Gets or sets whether this client is an admin. # # @params [Optional True/False] Should be true or false - default is false. # @return [True/False] The current value def admin(arg=nil) set_or_return( :admin, arg, :kind_of => [ TrueClass, FalseClass ] ) end # Gets or sets the public key. # # @params [Optional String] The string representation of the public key. # @return [String] The current value. def public_key(arg=nil) set_or_return( :public_key, arg, :kind_of => String ) end # Gets or sets whether this client is a validator. # # @params [Boolean] whether or not the client is a validator. If # `nil`, retrieves the already-set value. # @return [Boolean] The current value def validator(arg=nil) set_or_return( :validator, arg, :kind_of => [TrueClass, FalseClass] ) end # Gets or sets the private key. # # @params [Optional String] The string representation of the private key. # @return [String] The current value. def private_key(arg=nil) set_or_return( :private_key, arg, :kind_of => String ) end # The hash representation of the object. Includes the name and public_key. # Private key is included if available. # # @return [Hash] def to_hash result = { "name" => @name, "public_key" => @public_key, "validator" => @validator, "admin" => @admin, 'json_class' => self.class.name, "chef_type" => "client" } result["private_key"] = @private_key if @private_key result end # The JSON representation of the object. # # @return [String] the JSON string. def to_json(*a) to_hash.to_json(*a) end def self.json_create(o) client = Chef::ApiClient.new client.name(o["name"] || o["clientname"]) client.private_key(o["private_key"]) if o.key?("private_key") client.public_key(o["public_key"]) client.admin(o["admin"]) client.validator(o["validator"]) client end def self.http_api Chef::REST.new(Chef::Config[:chef_server_url]) end def self.reregister(name) api_client = load(name) api_client.reregister end def self.list(inflate=false) if inflate response = Hash.new Chef::Search::Query.new.search(:client) do |n| n = self.json_create(n) if n.instance_of?(Hash) response[n.name] = n end response else http_api.get("clients") end end # Load a client by name via the API def self.load(name) response = http_api.get("clients/#{name}") if response.kind_of?(Chef::ApiClient) response else client = Chef::ApiClient.new client.name(response['clientname']) client end end # Remove this client via the REST API def destroy http_api.delete("clients/#{@name}") end # Save this client via the REST API, returns a hash including the private key def save begin http_api.put("clients/#{name}", { :name => self.name, :admin => self.admin, :validator => self.validator}) rescue Net::HTTPServerException => e # If that fails, go ahead and try and update it if e.response.code == "404" http_api.post("clients", {:name => self.name, :admin => self.admin, :validator => self.validator }) else raise e end end end def reregister reregistered_self = http_api.put("clients/#{name}", { :name => name, :admin => admin, :validator => validator, :private_key => true }) if reregistered_self.respond_to?(:[]) private_key(reregistered_self["private_key"]) else private_key(reregistered_self.private_key) end self end # Create the client via the REST API def create http_api.post("clients", self) end # As a string def to_s "client[#{@name}]" end def inspect "Chef::ApiClient name:'#{name}' admin:'#{admin.inspect}' validator:'#{validator}' " + "public_key:'#{public_key}' private_key:'#{private_key}'" end def http_api @http_api ||= Chef::REST.new(Chef::Config[:chef_server_url]) end end end chef-11.8.2/lib/chef/reserved_names.rb0000644000004100000410000000046712254362222017551 0ustar www-datawww-dataclass Chef # This module exists to hide conflicting constant names from the DSL. # Hopefully we'll have a better/prettier/more sustainable solution in the # future, but for now this will fix a regression introduced in Chef 0.10.10 # (conflict with the Win32 namespace) module ReservedNames end end chef-11.8.2/lib/chef/version_class.rb0000644000004100000410000000340012254362222017407 0ustar www-datawww-data# Author:: Seth Falcon () # Author:: Christopher Walters () # Copyright:: Copyright 2010-2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. class Chef class Version include Comparable attr_reader :major, :minor, :patch def initialize(str="") parse(str) end def inspect "#{@major}.#{@minor}.#{@patch}" end def to_s "#{@major}.#{@minor}.#{@patch}" end def <=>(v) [:major, :minor, :patch].each do |method| ans = (self.send(method) <=> v.send(method)) return ans if ans != 0 end 0 end def hash # Didn't put any thought or research into this, probably can be # done better to_s.hash end # For hash def eql?(other) other.is_a?(Version) && self == other end protected def parse(str="") @major, @minor, @patch = case str.to_s when /^(\d+)\.(\d+)\.(\d+)$/ [ $1.to_i, $2.to_i, $3.to_i ] when /^(\d+)\.(\d+)$/ [ $1.to_i, $2.to_i, 0 ] else msg = "'#{str.to_s}' does not match 'x.y.z' or 'x.y'" raise Chef::Exceptions::InvalidCookbookVersion.new( msg ) end end end end chef-11.8.2/lib/chef/run_context/0000755000004100000410000000000012254362222016563 5ustar www-datawww-datachef-11.8.2/lib/chef/run_context/cookbook_compiler.rb0000644000004100000410000002441712254362222022620 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/log' require 'chef/recipe' require 'chef/resource/lwrp_base' require 'chef/provider/lwrp_base' require 'chef/resource_definition_list' class Chef class RunContext # Implements the compile phase of the chef run by loading/eval-ing files # from cookbooks in the correct order and in the correct context. class CookbookCompiler attr_reader :events attr_reader :run_list_expansion def initialize(run_context, run_list_expansion, events) @run_context = run_context @events = events @run_list_expansion = run_list_expansion @cookbook_order = nil end # Chef::Node object for the current run. def node @run_context.node end # Chef::CookbookCollection object for the current run def cookbook_collection @run_context.cookbook_collection end # Resource Definitions from the compiled cookbooks. This is populated by # calling #compile_resource_definitions (which is called by #compile) def definitions @run_context.definitions end # Run the compile phase of the chef run. Loads files in the following order: # * Libraries # * Attributes # * LWRPs # * Resource Definitions # * Recipes # # Recipes are loaded in precisely the order specified by the expanded run_list. # # Other files are loaded in an order derived from the expanded run_list # and the dependencies declared by cookbooks' metadata. See # #cookbook_order for more information. def compile compile_libraries compile_attributes compile_lwrps compile_resource_definitions compile_recipes end # Extracts the cookbook names from the expanded run list, then iterates # over the list, recursing through dependencies to give a run_list # ordered array of cookbook names with no duplicates. Dependencies appear # before the cookbook(s) that depend on them. def cookbook_order @cookbook_order ||= begin ordered_cookbooks = [] seen_cookbooks = {} run_list_expansion.recipes.each do |recipe| cookbook = Chef::Recipe.parse_recipe_name(recipe).first add_cookbook_with_deps(ordered_cookbooks, seen_cookbooks, cookbook) end Chef::Log.debug("Cookbooks to compile: #{ordered_cookbooks.inspect}") ordered_cookbooks end end # Loads library files from cookbooks according to #cookbook_order. def compile_libraries @events.library_load_start(count_files_by_segment(:libraries)) cookbook_order.each do |cookbook| load_libraries_from_cookbook(cookbook) end @events.library_load_complete end # Loads attributes files from cookbooks. Attributes files are loaded # according to #cookbook_order; within a cookbook, +default.rb+ is loaded # first, then the remaining attributes files in lexical sort order. def compile_attributes @events.attribute_load_start(count_files_by_segment(:attributes)) cookbook_order.each do |cookbook| load_attributes_from_cookbook(cookbook) end @events.attribute_load_complete end # Loads LWRPs according to #cookbook_order. Providers are loaded before # resources on a cookbook-wise basis. def compile_lwrps lwrp_file_count = count_files_by_segment(:providers) + count_files_by_segment(:resources) @events.lwrp_load_start(lwrp_file_count) cookbook_order.each do |cookbook| load_lwrps_from_cookbook(cookbook) end @events.lwrp_load_complete end # Loads resource definitions according to #cookbook_order def compile_resource_definitions @events.definition_load_start(count_files_by_segment(:definitions)) cookbook_order.each do |cookbook| load_resource_definitions_from_cookbook(cookbook) end @events.definition_load_complete end # Iterates over the expanded run_list, loading each recipe in turn. def compile_recipes @events.recipe_load_start(run_list_expansion.recipes.size) run_list_expansion.recipes.each do |recipe| begin @run_context.load_recipe(recipe) rescue Chef::Exceptions::RecipeNotFound => e @events.recipe_not_found(e) raise rescue Exception => e path = resolve_recipe(recipe) @events.recipe_file_load_failed(path, e) raise end end @events.recipe_load_complete end private def load_attributes_from_cookbook(cookbook_name) list_of_attr_files = files_in_cookbook_by_segment(cookbook_name, :attributes).dup if default_file = list_of_attr_files.find {|path| File.basename(path) == "default.rb" } list_of_attr_files.delete(default_file) load_attribute_file(cookbook_name.to_s, default_file) end list_of_attr_files.each do |filename| load_attribute_file(cookbook_name.to_s, filename) end end def load_attribute_file(cookbook_name, filename) Chef::Log.debug("Node #{node.name} loading cookbook #{cookbook_name}'s attribute file #{filename}") attr_file_basename = ::File.basename(filename, ".rb") node.include_attribute("#{cookbook_name}::#{attr_file_basename}") rescue Exception => e @events.attribute_file_load_failed(filename, e) raise end def load_libraries_from_cookbook(cookbook_name) files_in_cookbook_by_segment(cookbook_name, :libraries).each do |filename| begin Chef::Log.debug("Loading cookbook #{cookbook_name}'s library file: #{filename}") Kernel.load(filename) @events.library_file_loaded(filename) rescue Exception => e @events.library_file_load_failed(filename, e) raise end end end def load_lwrps_from_cookbook(cookbook_name) files_in_cookbook_by_segment(cookbook_name, :providers).each do |filename| load_lwrp_provider(cookbook_name, filename) end files_in_cookbook_by_segment(cookbook_name, :resources).each do |filename| load_lwrp_resource(cookbook_name, filename) end end def load_lwrp_provider(cookbook_name, filename) Chef::Log.debug("Loading cookbook #{cookbook_name}'s providers from #{filename}") Chef::Provider::LWRPBase.build_from_file(cookbook_name, filename, self) @events.lwrp_file_loaded(filename) rescue Exception => e @events.lwrp_file_load_failed(filename, e) raise end def load_lwrp_resource(cookbook_name, filename) Chef::Log.debug("Loading cookbook #{cookbook_name}'s resources from #{filename}") Chef::Resource::LWRPBase.build_from_file(cookbook_name, filename, self) @events.lwrp_file_loaded(filename) rescue Exception => e @events.lwrp_file_load_failed(filename, e) raise end def load_resource_definitions_from_cookbook(cookbook_name) files_in_cookbook_by_segment(cookbook_name, :definitions).each do |filename| begin Chef::Log.debug("Loading cookbook #{cookbook_name}'s definitions from #{filename}") resourcelist = Chef::ResourceDefinitionList.new resourcelist.from_file(filename) definitions.merge!(resourcelist.defines) do |key, oldval, newval| Chef::Log.info("Overriding duplicate definition #{key}, new definition found in #{filename}") newval end @events.definition_file_loaded(filename) rescue Exception => e @events.definition_file_load_failed(filename, e) raise end end end # Builds up the list of +ordered_cookbooks+ by first recursing through the # dependencies of +cookbook+, and then adding +cookbook+ to the list of # +ordered_cookbooks+. A cookbook is skipped if it appears in # +seen_cookbooks+, otherwise it is added to the set of +seen_cookbooks+ # before its dependencies are processed. def add_cookbook_with_deps(ordered_cookbooks, seen_cookbooks, cookbook) return false if seen_cookbooks.key?(cookbook) seen_cookbooks[cookbook] = true each_cookbook_dep(cookbook) do |dependency| add_cookbook_with_deps(ordered_cookbooks, seen_cookbooks, dependency) end ordered_cookbooks << cookbook end def count_files_by_segment(segment) cookbook_collection.inject(0) do |count, cookbook_by_name| count + cookbook_by_name[1].segment_filenames(segment).size end end # Lists the local paths to files in +cookbook+ of type +segment+ # (attribute, recipe, etc.), sorted lexically. def files_in_cookbook_by_segment(cookbook, segment) cookbook_collection[cookbook].segment_filenames(segment).sort end # Yields the name, as a symbol, of each cookbook depended on by # +cookbook_name+ in lexical sort order. def each_cookbook_dep(cookbook_name, &block) cookbook = cookbook_collection[cookbook_name] cookbook.metadata.dependencies.keys.sort.map{|x| x.to_sym}.each(&block) end # Given a +recipe_name+, finds the file associated with the recipe. def resolve_recipe(recipe_name) cookbook_name, recipe_short_name = Chef::Recipe.parse_recipe_name(recipe_name) cookbook = cookbook_collection[cookbook_name] cookbook.recipe_filenames_by_name[recipe_short_name] end end end end chef-11.8.2/lib/chef/resource/0000755000004100000410000000000012254362222016042 5ustar www-datawww-datachef-11.8.2/lib/chef/resource/yum_package.rb0000644000004100000410000000317212254362222020657 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/package' require 'chef/provider/package/yum' class Chef class Resource class YumPackage < Chef::Resource::Package def initialize(name, run_context=nil) super @resource_name = :yum_package @provider = Chef::Provider::Package::Yum @flush_cache = { :before => false, :after => false } @allow_downgrade = false end # Install a specific arch def arch(arg=nil) set_or_return( :arch, arg, :kind_of => [ String ] ) end def flush_cache(args={}) if args.is_a? Array args.each { |arg| @flush_cache[arg] = true } elsif args.any? @flush_cache = args else @flush_cache end end def allow_downgrade(arg=nil) set_or_return( :allow_downgrade, arg, :kind_of => [ TrueClass, FalseClass ] ) end end end end chef-11.8.2/lib/chef/resource/apt_package.rb0000644000004100000410000000224212254362222020626 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/package' require 'chef/provider/package/apt' class Chef class Resource class AptPackage < Chef::Resource::Package def initialize(name, run_context=nil) super @resource_name = :apt_package @provider = Chef::Provider::Package::Apt @default_release = nil end def default_release(arg=nil) set_or_return( :default_release, arg, :kind_of => [ String ] ) end end end end chef-11.8.2/lib/chef/resource/cookbook_file.rb0000644000004100000410000000307612254362222021202 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Seth Chisamore () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008, 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/file' require 'chef/provider/cookbook_file' require 'chef/mixin/securable' class Chef class Resource class CookbookFile < Chef::Resource::File include Chef::Mixin::Securable provides :cookbook_file, :on_platforms => :all def initialize(name, run_context=nil) super @provider = Chef::Provider::CookbookFile @resource_name = :cookbook_file @action = "create" @source = ::File.basename(name) @cookbook = nil @provider = Chef::Provider::CookbookFile end def source(source_filename=nil) set_or_return(:source, source_filename, :kind_of => String) end def cookbook(cookbook_name=nil) set_or_return(:cookbook, cookbook_name, :kind_of => String) end end end end chef-11.8.2/lib/chef/resource/ruby_block.rb0000644000004100000410000000245012254362222020523 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Resource class RubyBlock < Chef::Resource identity_attr :block_name def initialize(name, run_context=nil) super @resource_name = :ruby_block @action = "run" @allowed_actions << :create << :run @block_name = name end def block(&block) if block_given? and block @block = block else @block end end def block_name(arg=nil) set_or_return( :block_name, arg, :kind_of => String ) end end end end chef-11.8.2/lib/chef/resource/pacman_package.rb0000644000004100000410000000171312254362222021303 0ustar www-datawww-data# # Author:: Jan Zimmek () # Copyright:: Copyright (c) 2010 Jan Zimmek # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/package' class Chef class Resource class PacmanPackage < Chef::Resource::Package def initialize(name, run_context=nil) super @resource_name = :pacman_package @provider = Chef::Provider::Package::Pacman end end end end chef-11.8.2/lib/chef/resource/git.rb0000644000004100000410000000230512254362222017152 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require "chef/resource/scm" class Chef class Resource class Git < Chef::Resource::Scm def initialize(name, run_context=nil) super @resource_name = :git @provider = Chef::Provider::Git @additional_remotes = Hash[] end def additional_remotes(arg=nil) set_or_return( :additional_remotes, arg, :kind_of => Hash ) end alias :branch :revision alias :reference :revision alias :repo :repository end end end chef-11.8.2/lib/chef/resource/portage_package.rb0000644000004100000410000000172012254362222021503 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/package' class Chef class Resource class PortagePackage < Chef::Resource::Package def initialize(name, run_context=nil) super @resource_name = :portage_package @provider = Chef::Provider::Package::Portage end end end end chef-11.8.2/lib/chef/resource/directory.rb0000644000004100000410000000321112254362222020370 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Seth Chisamore () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008, 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource' require 'chef/provider/directory' require 'chef/mixin/securable' class Chef class Resource class Directory < Chef::Resource identity_attr :path state_attrs :group, :mode, :owner include Chef::Mixin::Securable provides :directory, :on_platforms => :all def initialize(name, run_context=nil) super @resource_name = :directory @path = name @action = :create @recursive = false @allowed_actions.push(:create, :delete) @provider = Chef::Provider::Directory end def recursive(arg=nil) set_or_return( :recursive, arg, :kind_of => [ TrueClass, FalseClass ] ) end def path(arg=nil) set_or_return( :path, arg, :kind_of => String ) end end end end chef-11.8.2/lib/chef/resource/http_request.rb0000644000004100000410000000305412254362222021120 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource' class Chef class Resource class HttpRequest < Chef::Resource identity_attr :url def initialize(name, run_context=nil) super @resource_name = :http_request @message = name @url = nil @action = :get @headers = {} @allowed_actions.push(:get, :put, :post, :delete, :head, :options) end def url(args=nil) set_or_return( :url, args, :kind_of => String ) end def message(args=nil, &block) args = block if block_given? set_or_return( :message, args, :kind_of => Object ) end def headers(args=nil) set_or_return( :headers, args, :kind_of => Hash ) end end end end chef-11.8.2/lib/chef/resource/breakpoint.rb0000644000004100000410000000176612254362222020537 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource' class Chef class Resource class Breakpoint < Chef::Resource def initialize(action="break", *args) @name = caller.first super(@name, *args) @action = "break" @allowed_actions << :break @provider = Chef::Provider::Breakpoint end end end end chef-11.8.2/lib/chef/resource/remote_directory.rb0000644000004100000410000000576512254362222021763 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/directory' require 'chef/provider/remote_directory' require 'chef/mixin/securable' class Chef class Resource class RemoteDirectory < Chef::Resource::Directory include Chef::Mixin::Securable provides :remote_directory, :on_platforms => :all identity_attr :path state_attrs :files_owner, :files_group, :files_mode def initialize(name, run_context=nil) super @resource_name = :remote_directory @path = name @source = ::File.basename(name) @delete = false @action = :create @recursive = true @purge = false @files_backup = 5 @files_owner = nil @files_group = nil @files_mode = 0644 unless Chef::Platform.windows? @overwrite = true @allowed_actions.push(:create, :create_if_missing, :delete) @cookbook = nil @provider = Chef::Provider::RemoteDirectory end if Chef::Platform.windows? # create a second instance of the 'rights' attribute rights_attribute(:files_rights) end def source(args=nil) set_or_return( :source, args, :kind_of => String ) end def files_backup(arg=nil) set_or_return( :files_backup, arg, :kind_of => [ Integer, FalseClass ] ) end def purge(arg=nil) set_or_return( :purge, arg, :kind_of => [ TrueClass, FalseClass ] ) end def files_group(arg=nil) set_or_return( :files_group, arg, :regex => Chef::Config[:group_valid_regex] ) end def files_mode(arg=nil) set_or_return( :files_mode, arg, :regex => /^\d{3,4}$/ ) end def files_owner(arg=nil) set_or_return( :files_owner, arg, :regex => Chef::Config[:user_valid_regex] ) end def overwrite(arg=nil) set_or_return( :overwrite, arg, :kind_of => [ TrueClass, FalseClass ] ) end def cookbook(args=nil) set_or_return( :cookbook, args, :kind_of => String ) end end end end chef-11.8.2/lib/chef/resource/scm.rb0000644000004100000410000000645312254362222017161 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource' class Chef class Resource class Scm < Chef::Resource identity_attr :destination state_attrs :revision def initialize(name, run_context=nil) super @destination = name @resource_name = :scm @enable_submodules = false @revision = "HEAD" @remote = "origin" @ssh_wrapper = nil @depth = nil @allowed_actions.push(:checkout, :export, :sync, :diff, :log) @action = [:sync] end def destination(arg=nil) set_or_return( :destination, arg, :kind_of => String ) end def repository(arg=nil) set_or_return( :repository, arg, :kind_of => String ) end def revision(arg=nil) set_or_return( :revision, arg, :kind_of => String ) end def user(arg=nil) set_or_return( :user, arg, :kind_of => [String, Integer] ) end def group(arg=nil) set_or_return( :group, arg, :kind_of => [String, Integer] ) end def svn_username(arg=nil) set_or_return( :svn_username, arg, :kind_of => String ) end def svn_password(arg=nil) set_or_return( :svn_password, arg, :kind_of => String ) end def svn_arguments(arg=nil) @svn_arguments, arg = nil, nil if arg == false set_or_return( :svn_arguments, arg, :kind_of => String ) end def svn_info_args(arg=nil) @svn_info_args, arg = nil, nil if arg == false set_or_return( :svn_info_args, arg, :kind_of => String) end # Capistrano and git-deploy use ``shallow clone'' def depth(arg=nil) set_or_return( :depth, arg, :kind_of => Integer ) end def enable_submodules(arg=nil) set_or_return( :enable_submodules, arg, :kind_of => [TrueClass, FalseClass] ) end def remote(arg=nil) set_or_return( :remote, arg, :kind_of => String ) end def ssh_wrapper(arg=nil) set_or_return( :ssh_wrapper, arg, :kind_of => String ) end def timeout(arg=nil) set_or_return( :timeout, arg, :kind_of => Integer ) end end end end chef-11.8.2/lib/chef/resource/easy_install_package.rb0000644000004100000410000000266212254362222022537 0ustar www-datawww-data# # Author:: Joe Williams () # Copyright:: Copyright (c) 2009 Joe Williams # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/package' class Chef class Resource class EasyInstallPackage < Chef::Resource::Package def initialize(name, run_context=nil) super @resource_name = :easy_install_package @provider = Chef::Provider::Package::EasyInstall end def easy_install_binary(arg=nil) set_or_return( :easy_install_binary, arg, :kind_of => [ String ] ) end def python_binary(arg=nil) set_or_return( :python_install_binary, arg, :kind_of => [ String ] ) end def module_name(arg=nil) set_or_return( :module_name, arg, :kind_of => [ String ] ) end end end end chef-11.8.2/lib/chef/resource/execute.rb0000644000004100000410000000522412254362222020034 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource' class Chef class Resource class Execute < Chef::Resource identity_attr :command def initialize(name, run_context=nil) super @resource_name = :execute @command = name @backup = 5 @action = "run" @creates = nil @cwd = nil @environment = nil @group = nil @path = nil @returns = 0 @timeout = nil @user = nil @allowed_actions.push(:run) @umask = nil end def umask(arg=nil) set_or_return( :umask, arg, :kind_of => [ String, Integer ] ) end def command(arg=nil) set_or_return( :command, arg, :kind_of => [ String, Array ] ) end def creates(arg=nil) set_or_return( :creates, arg, :kind_of => [ String ] ) end def cwd(arg=nil) set_or_return( :cwd, arg, :kind_of => [ String ] ) end def environment(arg=nil) set_or_return( :environment, arg, :kind_of => [ Hash ] ) end alias :env :environment def group(arg=nil) set_or_return( :group, arg, :kind_of => [ String, Integer ] ) end def path(arg=nil) set_or_return( :path, arg, :kind_of => [ Array ] ) end def returns(arg=nil) set_or_return( :returns, arg, :kind_of => [ Integer, Array ] ) end def timeout(arg=nil) set_or_return( :timeout, arg, :kind_of => [ Integer ] ) end def user(arg=nil) set_or_return( :user, arg, :kind_of => [ String, Integer ] ) end end end end chef-11.8.2/lib/chef/resource/ifconfig.rb0000644000004100000410000000564012254362222020160 0ustar www-datawww-data# # Author:: Jason K. Jackson (jasonjackson@gmail.com) # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2009 Jason K. Jackson # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource' class Chef class Resource class Ifconfig < Chef::Resource identity_attr :device state_attrs :inet_addr, :mask def initialize(name, run_context=nil) super @resource_name = :ifconfig @target = name @action = :add @allowed_actions.push(:add, :delete, :enable, :disable) @hwaddr = nil @mask = nil @inet_addr = nil @bcast = nil @mtu = nil @metric = nil @device = nil @onboot = nil @network = nil @bootproto = nil @onparent = nil end def target(arg=nil) set_or_return( :target, arg, :kind_of => String ) end def device(arg=nil) set_or_return( :device, arg, :kind_of => String ) end def hwaddr(arg=nil) set_or_return( :hwaddr, arg, :kind_of => String ) end def inet_addr(arg=nil) set_or_return( :inet_addr, arg, :kind_of => String ) end def bcast(arg=nil) set_or_return( :bcast, arg, :kind_of => String ) end def mask(arg=nil) set_or_return( :mask, arg, :kind_of => String ) end def mtu(arg=nil) set_or_return( :mtu, arg, :kind_of => String ) end def metric(arg=nil) set_or_return( :metric, arg, :kind_of => String ) end def onboot(arg=nil) set_or_return( :onboot, arg, :kind_of => String ) end def network(arg=nil) set_or_return( :network, arg, :kind_of => String ) end def bootproto(arg=nil) set_or_return( :bootproto, arg, :kind_of => String ) end def onparent(arg=nil) set_or_return( :onparent, arg, :kind_of => String ) end end end end chef-11.8.2/lib/chef/resource/mount.rb0000644000004100000410000000711712254362222017537 0ustar www-datawww-data# # Author:: Joshua Timberman () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2009 Opscode, Inc # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource' class Chef class Resource class Mount < Chef::Resource identity_attr :device state_attrs :mount_point, :device_type, :fstype, :username, :password, :domain def initialize(name, run_context=nil) super @resource_name = :mount @mount_point = name @device = nil @device_type = :device @fstype = "auto" @options = ["defaults"] @dump = 0 @pass = 2 @mounted = false @enabled = false @action = :mount @supports = { :remount => false } @allowed_actions.push(:mount, :umount, :remount, :enable, :disable) @username = nil @password = nil @domain = nil end def mount_point(arg=nil) set_or_return( :mount_point, arg, :kind_of => [ String ] ) end def device(arg=nil) set_or_return( :device, arg, :kind_of => [ String ] ) end def device_type(arg=nil) real_arg = arg.kind_of?(String) ? arg.to_sym : arg set_or_return( :device_type, real_arg, :equal_to => [ :device, :label, :uuid ] ) end def fstype(arg=nil) set_or_return( :fstype, arg, :kind_of => [ String ] ) end def options(arg=nil) if arg.is_a?(String) converted_arg = arg.gsub(/,/, ' ').split(/ /) else converted_arg = arg end set_or_return( :options, converted_arg, :kind_of => [ Array ] ) end def dump(arg=nil) set_or_return( :dump, arg, :kind_of => [ Integer, FalseClass ] ) end def pass(arg=nil) set_or_return( :pass, arg, :kind_of => [ Integer, FalseClass ] ) end def mounted(arg=nil) set_or_return( :mounted, arg, :kind_of => [ TrueClass, FalseClass ] ) end def enabled(arg=nil) set_or_return( :enabled, arg, :kind_of => [ TrueClass, FalseClass ] ) end def supports(args={}) if args.is_a? Array args.each { |arg| @supports[arg] = true } elsif args.any? @supports = args else @supports end end def username(arg=nil) set_or_return( :username, arg, :kind_of => [ String ] ) end def password(arg=nil) set_or_return( :password, arg, :kind_of => [ String ] ) end def domain(arg=nil) set_or_return( :domain, arg, :kind_of => [ String ] ) end end end end chef-11.8.2/lib/chef/resource/chef_gem.rb0000644000004100000410000000335712254362222020134 0ustar www-datawww-data# # Author:: Bryan McLellan # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/package' require 'chef/resource/gem_package' class Chef class Resource class ChefGem < Chef::Resource::Package::GemPackage provides :chef_gem, :on_platforms => :all def initialize(name, run_context=nil) super @resource_name = :chef_gem @provider = Chef::Provider::Package::Rubygems end # The chef_gem resources is for installing gems to the current gem environment only for use by Chef cookbooks. def gem_binary(arg=nil) if arg raise ArgumentError, "The chef_gem resource is restricted to the current gem environment, use gem_package to install to other environments." end nil end def after_created # Chef::Resource.run_action: Caveat: this skips Chef::Runner.run_action, where notifications are handled # Action could be an array of symbols, but probably won't (think install + enable for a package) Array(@action).each do |action| self.run_action(action) end Gem.clear_paths end end end end chef-11.8.2/lib/chef/resource/erl_call.rb0000644000004100000410000000410512254362222020144 0ustar www-datawww-data# # Author:: Joe Williams () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2009 Joe Williams # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource' class Chef class Resource class ErlCall < Chef::Resource # erl_call : http://erlang.org/doc/man/erl_call.html identity_attr :code def initialize(name, run_context=nil) super @resource_name = :erl_call @code = "q()." # your erlang code goes here @cookie = nil # cookie of the erlang node @distributed = false # if you want to have a distributed erlang node @name_type = "sname" # type of erlang hostname name or sname @node_name = "chef@localhost" # the erlang node hostname @action = "run" @allowed_actions.push(:run) end def code(arg=nil) set_or_return( :code, arg, :kind_of => [ String ] ) end def cookie(arg=nil) set_or_return( :cookie, arg, :kind_of => [ String ] ) end def distributed(arg=nil) set_or_return( :distributed, arg, :kind_of => [ TrueClass, FalseClass ] ) end def name_type(arg=nil) set_or_return( :name_type, arg, :kind_of => [ String ] ) end def node_name(arg=nil) set_or_return( :node_name, arg, :kind_of => [ String ] ) end end end end chef-11.8.2/lib/chef/resource/ruby.rb0000644000004100000410000000164212254362222017353 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/script' class Chef class Resource class Ruby < Chef::Resource::Script def initialize(name, run_context=nil) super @resource_name = :ruby @interpreter = "ruby" end end end end chef-11.8.2/lib/chef/resource/deploy_revision.rb0000644000004100000410000000227212254362222021604 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 Daniel DeLeo # License:: Apache License, Version 2.0 # # 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. # class Chef class Resource # Convenience class for using the deploy resource with the revision # deployment strategy (provider) class DeployRevision < Chef::Resource::Deploy def initialize(*args, &block) super @resource_name = :deploy_revision @provider = Chef::Provider::Deploy::Revision end end class DeployBranch < Chef::Resource::DeployRevision def initialize(*args, &block) super @resource_name = :deploy_branch end end end end chef-11.8.2/lib/chef/resource/ips_package.rb0000644000004100000410000000240612254362222020637 0ustar www-datawww-data# # Author:: Jason Williams () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/package' require 'chef/provider/package/ips' class Chef class Resource class IpsPackage < ::Chef::Resource::Package def initialize(name, run_context = nil) super(name, run_context) @resource_name = :ips_package @provider = Chef::Provider::Package::Ips @allowed_actions = [ :install, :remove, :upgrade ] @accept_license = false end def accept_license(arg=nil) set_or_return( :purge, arg, :kind_of => [ TrueClass, FalseClass ] ) end end end end chef-11.8.2/lib/chef/resource/solaris_package.rb0000644000004100000410000000205612254362222021521 0ustar www-datawww-data# # Author:: Toomas Pelberg () # Author:: Prabhu Das () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/package' require 'chef/provider/package/solaris' class Chef class Resource class SolarisPackage < Chef::Resource::Package def initialize(name, run_context=nil) super @resource_name = :solaris_package @provider = Chef::Provider::Package::Solaris end end end end chef-11.8.2/lib/chef/resource/conditional.rb0000644000004100000410000000545712254362222020705 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/mixin/shell_out' class Chef class Resource class Conditional include Chef::Mixin::ShellOut # We only create these via the `not_if` or `only_if` constructors, and # not the default constructor class << self private :new end def self.not_if(command=nil, command_opts={}, &block) new(:not_if, command, command_opts, &block) end def self.only_if(command=nil, command_opts={}, &block) new(:only_if, command, command_opts, &block) end attr_reader :positivity attr_reader :command attr_reader :command_opts attr_reader :block def initialize(positivity, command=nil, command_opts={}, &block) @positivity = positivity case command when String @command, @command_opts = command, command_opts @block = nil when nil raise ArgumentError, "only_if/not_if requires either a command or a block" unless block_given? @command, @command_opts = nil, nil @block = block else raise ArgumentError, "Invalid only_if/not_if command: #{command.inspect} (#{command.class})" end end def continue? case @positivity when :only_if evaluate when :not_if !evaluate else raise "Cannot evaluate resource conditional of type #{@positivity}" end end def evaluate @command ? evaluate_command : evaluate_block end def evaluate_command shell_out(@command, @command_opts).status.success? rescue Chef::Exceptions::CommandTimeout Chef::Log.warn "Command '#{@command}' timed out" false end def evaluate_block @block.call end def short_description @positivity end def description cmd_or_block = @command ? "command `#{@command}`" : "ruby block" "#{@positivity} #{cmd_or_block}" end def to_text if @command "#{positivity} \"#{@command}\"" else "#{@positivity} { #code block }" end end end end end chef-11.8.2/lib/chef/resource/freebsd_package.rb0000644000004100000410000000177312254362222021464 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/package' require 'chef/provider/package/freebsd' class Chef class Resource class FreebsdPackage < Chef::Resource::Package def initialize(name, run_context=nil) super @resource_name = :freebsd_package @provider = Chef::Provider::Package::Freebsd end end end end chef-11.8.2/lib/chef/resource/macports_package.rb0000644000004100000410000000166712254362222021704 0ustar www-datawww-data# # Author:: David Balatero () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Resource class MacportsPackage < Chef::Resource::Package def initialize(name, run_context=nil) super @resource_name = :macports_package @provider = Chef::Provider::Package::Macports end end end end chef-11.8.2/lib/chef/resource/gem_package.rb0000644000004100000410000000332512254362222020615 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/package' class Chef class Resource class GemPackage < Chef::Resource::Package def initialize(name, run_context=nil) super @resource_name = :gem_package @provider = Chef::Provider::Package::Rubygems end def source(arg=nil) set_or_return(:source, arg, :kind_of => [ String, Array ]) end # Sets a custom gem_binary to run for gem commands. def gem_binary(gem_cmd=nil) set_or_return(:gem_binary,gem_cmd,:kind_of => [ String ]) end ## # Options for the gem install, either a Hash or a String. When a hash is # given, the options are passed to Gem::DependencyInstaller.new, and the # gem will be installed via the gems API. When a String is given, the gem # will be installed by shelling out to the gem command. Using a Hash of # options with an explicit gem_binary will result in undefined behavior. def options(opts=nil) set_or_return(:options,opts,:kind_of => [String,Hash]) end end end end chef-11.8.2/lib/chef/resource/lwrp_base.rb0000644000004100000410000001054212254362222020347 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Walters () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008-2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource' class Chef class Resource # == Chef::Resource::LWRPBase # Base class for LWRP resources. Adds DSL sugar on top of Chef::Resource, # so attributes, default action, etc. can be defined with pleasing syntax. class LWRPBase < Resource NULL_ARG = Object.new extend Chef::Mixin::ConvertToClassName extend Chef::Mixin::FromFile # Evaluates the LWRP resource file and instantiates a new Resource class. def self.build_from_file(cookbook_name, filename, run_context) rname = filename_to_qualified_string(cookbook_name, filename) # Add log entry if we override an existing light-weight resource. class_name = convert_to_class_name(rname) if Resource.strict_const_defined?(class_name) old_class = Resource.send(:remove_const, class_name) # CHEF-3432 -- Chef::Resource keeps a list of subclasses; need to # remove old ones from the list when replacing. resource_classes.delete(old_class) Chef::Log.info("#{class_name} light-weight resource already initialized -- overriding!") end resource_class = Class.new(self) resource_class.resource_name = rname resource_class.run_context = run_context resource_class.class_from_file(filename) Chef::Resource.const_set(class_name, resource_class) Chef::Log.debug("Loaded contents of #{filename} into a resource named #{rname} defined in Chef::Resource::#{class_name}") resource_class end # Set the resource snake_case name. Should only be called via # build_from_file. def self.resource_name=(resource_name) @resource_name = resource_name end # Returns the resource snake_case name def self.resource_name @resource_name end # Define an attribute on this resource, including optional validation # parameters. def self.attribute(attr_name, validation_opts={}) # Ruby 1.8 doesn't support default arguments to blocks, but we have to # use define_method with a block to capture +validation_opts+. # Workaround this by defining two methods :( class_eval(<<-SHIM, __FILE__, __LINE__) def #{attr_name}(arg=nil) _set_or_return_#{attr_name}(arg) end SHIM define_method("_set_or_return_#{attr_name.to_s}".to_sym) do |arg| set_or_return(attr_name.to_sym, arg, validation_opts) end end # Sets the default action def self.default_action(action_name=NULL_ARG) unless action_name.equal?(NULL_ARG) valid_actions.push(action_name) @default_action = action_name end @default_action end # Adds +action_names+ to the list of valid actions for this resource. def self.actions(*action_names) valid_actions.push(*action_names) end def self.valid_actions @valid_actions ||= [] end # Set the run context on the class. Used to provide access to the node # during class definition. def self.run_context=(run_context) @run_context = run_context end def self.run_context @run_context end def self.node run_context.node end # Default initializer. Sets the default action and allowed actions. def initialize(name, run_context=nil) super(name, run_context) @resource_name = self.class.resource_name.to_sym @action = self.class.default_action allowed_actions.push(self.class.valid_actions).flatten! end end end end chef-11.8.2/lib/chef/resource/python.rb0000644000004100000410000000165012254362222017712 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/script' class Chef class Resource class Python < Chef::Resource::Script def initialize(name, run_context=nil) super @resource_name = :python @interpreter = "python" end end end end chef-11.8.2/lib/chef/resource/ohai.rb0000644000004100000410000000250712254362222017313 0ustar www-datawww-data# # Author:: Michael Leinartas () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2010 Michael Leinartas # License:: Apache License, Version 2.0 # # 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. # class Chef class Resource class Ohai < Chef::Resource identity_attr :name state_attrs :plugin def initialize(name, run_context=nil) super @resource_name = :ohai @name = name @allowed_actions.push(:reload) @action = :reload @plugin = nil end def plugin(arg=nil) set_or_return( :plugin, arg, :kind_of => [ String ] ) end def name(arg=nil) set_or_return( :name, arg, :kind_of => [ String ] ) end end end end chef-11.8.2/lib/chef/resource/bff_package.rb0000644000004100000410000000177012254362222020604 0ustar www-datawww-data# # Author:: Deepali Jagtap () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/package' require 'chef/provider/package/aix' class Chef class Resource class BffPackage < Chef::Resource::Package def initialize(name, run_context=nil) super @resource_name = :bff_package @provider = Chef::Provider::Package::Aix end end end end chef-11.8.2/lib/chef/resource/registry_key.rb0000644000004100000410000000531312254362222021111 0ustar www-datawww-data# Author:: Prajakta Purohit () # Author:: Lamont Granquist () # # Copyright:: 2011, 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. # require 'chef/provider/registry_key' require 'chef/resource' class Chef class Resource class RegistryKey < Chef::Resource identity_attr :key state_attrs :values def initialize(name, run_context=nil) super @resource_name = :registry_key @action = :create @architecture = :machine @recursive = false @key = name @values = [] @allowed_actions.push(:create, :create_if_missing, :delete, :delete_key) end def key(arg=nil) set_or_return( :key, arg, :kind_of => String ) end def values(arg=nil) if not arg.nil? if arg.is_a?(Hash) @values = [ arg ] elsif arg.is_a?(Array) @values = arg else raise ArgumentError, "Bad type for RegistryKey resource, use Hash or Array" end @values.each do |v| raise ArgumentError, "Missing name key in RegistryKey values hash" unless v.has_key?(:name) raise ArgumentError, "Missing type key in RegistryKey values hash" unless v.has_key?(:type) raise ArgumentError, "Missing data key in RegistryKey values hash" unless v.has_key?(:data) v.each_key do |key| raise ArgumentError, "Bad key #{key} in RegistryKey values hash" unless [:name,:type,:data].include?(key) end raise ArgumentError, "Type of name => #{v[:name]} should be string" unless v[:name].is_a?(String) raise Argument Error "Type of type => #{v[:name]} should be symbol" unless v[:type].is_a?(Symbol) end elsif self.instance_variable_defined?(:@values) == true @values end end def recursive(arg=nil) set_or_return( :recursive, arg, :kind_of => [TrueClass, FalseClass] ) end def architecture(arg=nil) set_or_return( :architecture, arg, :kind_of => Symbol ) end end end end chef-11.8.2/lib/chef/resource/link.rb0000644000004100000410000000534612254362222017334 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource' require 'chef/mixin/securable' class Chef class Resource class Link < Chef::Resource include Chef::Mixin::Securable provides :link, :on_platform => :all identity_attr :target_file state_attrs :to, :owner, :group def initialize(name, run_context=nil) verify_links_supported! super @resource_name = :link @to = nil @action = :create @link_type = :symbolic @target_file = name @allowed_actions.push(:create, :delete) @provider = Chef::Provider::Link end def to(arg=nil) set_or_return( :to, arg, :kind_of => String ) end def target_file(arg=nil) set_or_return( :target_file, arg, :kind_of => String ) end def link_type(arg=nil) real_arg = arg.kind_of?(String) ? arg.to_sym : arg set_or_return( :link_type, real_arg, :equal_to => [ :symbolic, :hard ] ) end def group(arg=nil) set_or_return( :group, arg, :regex => Chef::Config[:group_valid_regex] ) end def owner(arg=nil) set_or_return( :owner, arg, :regex => Chef::Config[:user_valid_regex] ) end # make link quack like a file (XXX: not for public consumption) def path @target_file end private def verify_links_supported! # On certain versions of windows links are not supported. Make # sure we are not on such a platform. if Chef::Platform.windows? require 'chef/win32/file' begin Chef::ReservedNames::Win32::File.verify_links_supported! rescue Chef::Exceptions::Win32APIFunctionNotImplemented => e Chef::Log.fatal("Link resource is not supported on this version of Windows") raise e end end end end end end chef-11.8.2/lib/chef/resource/windows_script.rb0000644000004100000410000000344712254362222021455 0ustar www-datawww-data# # Author:: Adam Edwards () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/script' require 'chef/mixin/windows_architecture_helper' class Chef class Resource class WindowsScript < Chef::Resource::Script protected def initialize(name, run_context, resource_name, interpreter_command) super(name, run_context) @interpreter = interpreter_command @resource_name = resource_name end include Chef::Mixin::WindowsArchitectureHelper public def architecture(arg=nil) assert_architecture_compatible!(arg) if ! arg.nil? result = set_or_return( :architecture, arg, :kind_of => Symbol ) end protected def assert_architecture_compatible!(desired_architecture) if ! node_supports_windows_architecture?(node, desired_architecture) raise Chef::Exceptions::Win32ArchitectureIncorrect, "cannot execute script with requested architecture '#{desired_architecture.to_s}' on a system with architecture '#{node_windows_architecture(node)}'" end end def node run_context && run_context.node end end end end chef-11.8.2/lib/chef/resource/dpkg_package.rb0000644000004100000410000000175412254362222020776 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/package' require 'chef/provider/package/dpkg' class Chef class Resource class DpkgPackage < Chef::Resource::Package def initialize(name, run_context=nil) super @resource_name = :dpkg_package @provider = Chef::Provider::Package::Dpkg end end end end chef-11.8.2/lib/chef/resource/smartos_package.rb0000644000004100000410000000216012254362222021531 0ustar www-datawww-data# # Author:: Toomas Pelberg () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/package' require 'chef/provider/package/smartos' class Chef class Resource class SmartosPackage < Chef::Resource::Package def initialize(name, run_context=nil) super @resource_name = :smartos_package @provider = Chef::Provider::Package::SmartOS end end end end # Backwards compatability # @todo remove in Chef 12 Chef::Resource::SmartOSPackage = Chef::Resource::SmartosPackage chef-11.8.2/lib/chef/resource/user.rb0000644000004100000410000000546112254362222017353 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource' class Chef class Resource class User < Chef::Resource identity_attr :username state_attrs :uid, :gid, :home def initialize(name, run_context=nil) super @resource_name = :user @username = name @comment = nil @uid = nil @gid = nil @home = nil @shell = nil @password = nil @system = false @manage_home = false @non_unique = false @action = :create @supports = { :manage_home => false, :non_unique => false } @allowed_actions.push(:create, :remove, :modify, :manage, :lock, :unlock) end def username(arg=nil) set_or_return( :username, arg, :kind_of => [ String ] ) end def comment(arg=nil) set_or_return( :comment, arg, :kind_of => [ String ] ) end def uid(arg=nil) set_or_return( :uid, arg, :kind_of => [ String, Integer ] ) end def gid(arg=nil) set_or_return( :gid, arg, :kind_of => [ String, Integer ] ) end alias_method :group, :gid def home(arg=nil) set_or_return( :home, arg, :kind_of => [ String ] ) end def shell(arg=nil) set_or_return( :shell, arg, :kind_of => [ String ] ) end def password(arg=nil) set_or_return( :password, arg, :kind_of => [ String ] ) end def system(arg=nil) set_or_return( :system, arg, :kind_of => [ TrueClass, FalseClass ] ) end def manage_home(arg=nil) set_or_return( :manage_home, arg, :kind_of => [ TrueClass, FalseClass ] ) end def non_unique(arg=nil) set_or_return( :non_unique, arg, :kind_of => [ TrueClass, FalseClass ] ) end end end end chef-11.8.2/lib/chef/resource/file.rb0000644000004100000410000000556612254362222017322 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2008, 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource' require 'chef/platform/query_helpers' require 'chef/provider/file' require 'chef/mixin/securable' class Chef class Resource class File < Chef::Resource include Chef::Mixin::Securable identity_attr :path if Platform.windows? # Use Windows rights instead of standard *nix permissions state_attrs :checksum, :rights, :deny_rights else state_attrs :checksum, :owner, :group, :mode end attr_writer :checksum provides :file, :on_platforms => :all def initialize(name, run_context=nil) super @resource_name = :file @path = name @backup = 5 @action = "create" @allowed_actions.push(:create, :delete, :touch, :create_if_missing) @provider = Chef::Provider::File @atomic_update = Chef::Config[:file_atomic_update] @force_unlink = false @manage_symlink_source = nil @diff = nil end def content(arg=nil) set_or_return( :content, arg, :kind_of => String ) end def backup(arg=nil) set_or_return( :backup, arg, :kind_of => [ Integer, FalseClass ] ) end def checksum(arg=nil) set_or_return( :checksum, arg, :regex => /^[a-zA-Z0-9]{64}$/ ) end def path(arg=nil) set_or_return( :path, arg, :kind_of => String ) end def diff(arg=nil) set_or_return( :diff, arg, :kind_of => String ) end def atomic_update(arg=nil) set_or_return( :atomic_update, arg, :kind_of => [ TrueClass, FalseClass ] ) end def force_unlink(arg=nil) set_or_return( :force_unlink, arg, :kind_of => [ TrueClass, FalseClass ] ) end def manage_symlink_source(arg=nil) set_or_return( :manage_symlink_source, arg, :kind_of => [ TrueClass, FalseClass ] ) end end end end chef-11.8.2/lib/chef/resource/mdadm.rb0000644000004100000410000000430512254362222017453 0ustar www-datawww-data# # Author:: Joe Williams () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2009 Joe Williams # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource' class Chef class Resource class Mdadm < Chef::Resource identity_attr :raid_device state_attrs :devices, :level, :chunk def initialize(name, run_context=nil) super @resource_name = :mdadm @chunk = 16 @devices = [] @exists = false @level = 1 @metadata = "0.90" @bitmap = nil @raid_device = name @action = :create @allowed_actions.push(:create, :assemble, :stop) end def chunk(arg=nil) set_or_return( :chunk, arg, :kind_of => [ Integer ] ) end def devices(arg=nil) set_or_return( :devices, arg, :kind_of => [ Array ] ) end def exists(arg=nil) set_or_return( :exists, arg, :kind_of => [ TrueClass, FalseClass ] ) end def level(arg=nil) set_or_return( :level, arg, :kind_of => [ Integer ] ) end def metadata(arg=nil) set_or_return( :metadata, arg, :kind_of => [ String ] ) end def bitmap(arg=nil) set_or_return( :bitmap, arg, :kind_of => [ String ] ) end def raid_device(arg=nil) set_or_return( :raid_device, arg, :kind_of => [ String ] ) end end end end chef-11.8.2/lib/chef/resource/powershell_script.rb0000644000004100000410000000167512254362222022150 0ustar www-datawww-data# # Author:: Adam Edwards () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/windows_script' class Chef class Resource class PowershellScript < Chef::Resource::WindowsScript def initialize(name, run_context=nil) super(name, run_context, :powershell_script, "powershell.exe") end end end end chef-11.8.2/lib/chef/resource/script.rb0000644000004100000410000000272012254362222017674 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/execute' class Chef class Resource class Script < Chef::Resource::Execute identity_attr :command def initialize(name, run_context=nil) super @resource_name = :script @command = name @code = nil @interpreter = nil @flags = nil end def code(arg=nil) set_or_return( :code, arg, :kind_of => [ String ] ) end def interpreter(arg=nil) set_or_return( :interpreter, arg, :kind_of => [ String ] ) end def flags(arg=nil) set_or_return( :flags, arg, :kind_of => [ String ] ) end end end end chef-11.8.2/lib/chef/resource/cron.rb0000644000004100000410000001042112254362222017326 0ustar www-datawww-data# # Author:: Bryan McLellan (btm@loftninjas.org) # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2009 Bryan McLellan # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource' class Chef class Resource class Cron < Chef::Resource identity_attr :command state_attrs :minute, :hour, :day, :month, :weekday, :user def initialize(name, run_context=nil) super @resource_name = :cron @action = :create @allowed_actions.push(:create, :delete) @minute = "*" @hour = "*" @day = "*" @month = "*" @weekday = "*" @command = nil @user = "root" @mailto = nil @path = nil @shell = nil @home = nil @environment = {} end def minute(arg=nil) if arg.is_a?(Integer) converted_arg = arg.to_s else converted_arg = arg end begin if integerize(arg) > 59 then raise RangeError end rescue ArgumentError end set_or_return( :minute, converted_arg, :kind_of => String ) end def hour(arg=nil) if arg.is_a?(Integer) converted_arg = arg.to_s else converted_arg = arg end begin if integerize(arg) > 23 then raise RangeError end rescue ArgumentError end set_or_return( :hour, converted_arg, :kind_of => String ) end def day(arg=nil) if arg.is_a?(Integer) converted_arg = arg.to_s else converted_arg = arg end begin if integerize(arg) > 31 then raise RangeError end rescue ArgumentError end set_or_return( :day, converted_arg, :kind_of => String ) end def month(arg=nil) if arg.is_a?(Integer) converted_arg = arg.to_s else converted_arg = arg end begin if integerize(arg) > 12 then raise RangeError end rescue ArgumentError end set_or_return( :month, converted_arg, :kind_of => String ) end def weekday(arg=nil) if arg.is_a?(Integer) converted_arg = arg.to_s else converted_arg = arg end begin if integerize(arg) > 7 then raise RangeError end rescue ArgumentError end set_or_return( :weekday, converted_arg, :kind_of => String ) end def mailto(arg=nil) set_or_return( :mailto, arg, :kind_of => String ) end def path(arg=nil) set_or_return( :path, arg, :kind_of => String ) end def home(arg=nil) set_or_return( :home, arg, :kind_of => String ) end def shell(arg=nil) set_or_return( :shell, arg, :kind_of => String ) end def command(arg=nil) set_or_return( :command, arg, :kind_of => String ) end def user(arg=nil) set_or_return( :user, arg, :kind_of => String ) end def environment(arg=nil) set_or_return( :environment, arg, :kind_of => Hash ) end private # On Ruby 1.8, Kernel#Integer will happily do this for you. On 1.9, no. def integerize(integerish) Integer(integerish) rescue TypeError 0 end end end end chef-11.8.2/lib/chef/resource/log.rb0000644000004100000410000000373012254362222017153 0ustar www-datawww-data# # Author:: Cary Penniman () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Resource class Log < Chef::Resource identity_attr :message # Sends a string from a recipe to a log provider # # log "some string to log" do # level :info # (default) also supports :warn, :debug, and :error # end # # === Example # log "your string to log" # # or # # log "a debug string" { level :debug } # # Initialize log resource with a name as the string to log # # === Parameters # name:: Message to log # collection:: Collection of included recipes # node:: Node where resource will be used def initialize(name, run_context=nil) super @resource_name = :log @level = :info @action = :write @allowed_actions.push(:write) @message = name end def message(arg=nil) set_or_return( :message, arg, :kind_of => String ) end # Log level, one of :debug, :info, :warn, :error or :fatal def level(arg=nil) set_or_return( :level, arg, :equal_to => [ :debug, :info, :warn, :error, :fatal ] ) end end end end chef-11.8.2/lib/chef/resource/rpm_package.rb0000644000004100000410000000176212254362222020646 0ustar www-datawww-data# # Author:: Thomas Bishop () # Copyright:: Copyright (c) 2010 Thomas Bishop # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/package' require 'chef/provider/package/rpm' class Chef class Resource class RpmPackage < Chef::Resource::Package def initialize(name, run_context=nil) super @resource_name = :rpm_package @provider = Chef::Provider::Package::Rpm end end end end chef-11.8.2/lib/chef/resource/package.rb0000644000004100000410000000364712254362222017774 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource' class Chef class Resource class Package < Chef::Resource identity_attr :package_name state_attrs :version, :options def initialize(name, run_context=nil) super @action = :install @allowed_actions.push(:install, :upgrade, :remove, :purge, :reconfig) @candidate_version = nil @options = nil @package_name = name @resource_name = :package @response_file = nil @source = nil @version = nil end def package_name(arg=nil) set_or_return( :package_name, arg, :kind_of => [ String ] ) end def version(arg=nil) set_or_return( :version, arg, :kind_of => [ String ] ) end def response_file(arg=nil) set_or_return( :response_file, arg, :kind_of => [ String ] ) end def source(arg=nil) set_or_return( :source, arg, :kind_of => [ String ] ) end def options(arg=nil) set_or_return( :options, arg, :kind_of => [ String ] ) end end end end chef-11.8.2/lib/chef/resource/group.rb0000644000004100000410000000421012254362222017520 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Resource class Group < Chef::Resource identity_attr :group_name state_attrs :members def initialize(name, run_context=nil) super @resource_name = :group @group_name = name @gid = nil @members = [] @action = :create @append = false @non_unique = false @allowed_actions.push(:create, :remove, :modify, :manage) end def group_name(arg=nil) set_or_return( :group_name, arg, :kind_of => [ String ] ) end def gid(arg=nil) set_or_return( :gid, arg, :kind_of => [ String, Integer ] ) end def members(arg=nil) converted_members = arg.is_a?(String) ? [].push(arg) : arg set_or_return( :members, converted_members, :kind_of => [ Array ] ) end alias_method :users, :members def append(arg=nil) set_or_return( :append, arg, :kind_of => [ TrueClass, FalseClass ] ) end def system(arg=nil) set_or_return( :system, arg, :kind_of => [ TrueClass, FalseClass ] ) end def non_unique(arg=nil) set_or_return( :non_unique, arg, :kind_of => [ TrueClass, FalseClass ] ) end end end end chef-11.8.2/lib/chef/resource/subversion.rb0000644000004100000410000000215012254362222020564 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require "chef/resource/scm" class Chef class Resource class Subversion < Chef::Resource::Scm def initialize(name, run_context=nil) super @svn_arguments = '--no-auth-cache' @svn_info_args = '--no-auth-cache' @resource_name = :subversion @provider = Chef::Provider::Subversion allowed_actions << :force_export end end end end chef-11.8.2/lib/chef/resource/timestamped_deploy.rb0000644000004100000410000000200212254362222022251 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 Daniel DeLeo # License:: Apache License, Version 2.0 # # 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. # class Chef class Resource # Convenience class for using the deploy resource with the timestamped # deployment strategy (provider) class TimestampedDeploy < Chef::Resource::Deploy def initialize(*args, &block) super(*args, &block) @provider = Chef::Provider::Deploy::Timestamped end end end end chef-11.8.2/lib/chef/resource/bash.rb0000644000004100000410000000164212254362222017307 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/script' class Chef class Resource class Bash < Chef::Resource::Script def initialize(name, run_context=nil) super @resource_name = :bash @interpreter = "bash" end end end end chef-11.8.2/lib/chef/resource/perl.rb0000644000004100000410000000164212254362222017334 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/script' class Chef class Resource class Perl < Chef::Resource::Script def initialize(name, run_context=nil) super @resource_name = :perl @interpreter = "perl" end end end end chef-11.8.2/lib/chef/resource/remote_file.rb0000644000004100000410000000640512254362222020666 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2008, 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/file' require 'chef/provider/remote_file' require 'chef/mixin/securable' class Chef class Resource class RemoteFile < Chef::Resource::File include Chef::Mixin::Securable provides :remote_file, :on_platforms => :all def initialize(name, run_context=nil) super @resource_name = :remote_file @action = "create" @source = [] @use_etag = true @use_last_modified = true @ftp_active_mode = false @headers = {} @provider = Chef::Provider::RemoteFile end def source(*args) if not args.empty? args = Array(args).flatten validate_source(args) @source = args elsif self.instance_variable_defined?(:@source) == true @source end end def checksum(args=nil) set_or_return( :checksum, args, :kind_of => String ) end # Disable or enable ETag and Last Modified conditional GET. Equivalent to # use_etag(true_or_false) # use_last_modified(true_or_false) def use_conditional_get(true_or_false) use_etag(true_or_false) use_last_modified(true_or_false) end def use_etag(args=nil) set_or_return( :use_etag, args, :kind_of => [ TrueClass, FalseClass ] ) end alias :use_etags :use_etag def use_last_modified(args=nil) set_or_return( :use_last_modified, args, :kind_of => [ TrueClass, FalseClass ] ) end def ftp_active_mode(args=nil) set_or_return( :ftp_active_mode, args, :kind_of => [ TrueClass, FalseClass ] ) end def headers(args=nil) set_or_return( :headers, args, :kind_of => Hash ) end def after_created validate_source(@source) end private def validate_source(source) raise ArgumentError, "#{resource_name} has an empty source" if source.empty? source.each do |src| unless absolute_uri?(src) raise Exceptions::InvalidRemoteFileURI, "#{src.inspect} is not a valid `source` parameter for #{resource_name}. `source` must be an absolute URI or an array of URIs." end end end def absolute_uri?(source) source.kind_of?(String) and URI.parse(source).absolute? rescue URI::InvalidURIError false end end end end chef-11.8.2/lib/chef/resource/env.rb0000644000004100000410000000276412254362222017170 0ustar www-datawww-data# # Author:: Doug MacEachern () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2010 VMware, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Resource class Env < Chef::Resource identity_attr :key_name state_attrs :value def initialize(name, run_context=nil) super @resource_name = :env @key_name = name @value = nil @action = :create @delim = nil @allowed_actions.push(:create, :delete, :modify) end def key_name(arg=nil) set_or_return( :key_name, arg, :kind_of => [ String ] ) end def value(arg=nil) set_or_return( :value, arg, :kind_of => [ String ] ) end def delim(arg=nil) set_or_return( :delim, arg, :kind_of => [ String ] ) end end end end chef-11.8.2/lib/chef/resource/deploy.rb0000644000004100000410000002672412254362222017676 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # # EX: # deploy "/my/deploy/dir" do # repo "git@github.com/whoami/project" # revision "abc123" # or "HEAD" or "TAG_for_1.0" or (subversion) "1234" # user "deploy_ninja" # enable_submodules true # migrate true # migration_command "rake db:migrate" # environment "RAILS_ENV" => "production", "OTHER_ENV" => "foo" # shallow_clone true # action :deploy # or :rollback # restart_command "touch tmp/restart.txt" # git_ssh_wrapper "wrap-ssh4git.sh" # scm_provider Chef::Provider::Git # is the default, for svn: Chef::Provider::Subversion # svn_username "whoami" # svn_password "supersecret" # end require "chef/resource/scm" class Chef class Resource # Deploy: Deploy apps from a source control repository. # # Callbacks: # Callbacks can be a block or a string. If given a block, the code # is evaluated as an embedded recipe, and run at the specified # point in the deploy process. If given a string, the string is taken as # a path to a callback file/recipe. Paths are evaluated relative to the # release directory. Callback files can contain chef code (resources, etc.) # class Deploy < Chef::Resource provider_base Chef::Provider::Deploy identity_attr :repository state_attrs :deploy_to, :revision def initialize(name, run_context=nil) super @resource_name = :deploy @deploy_to = name @environment = nil @repository_cache = 'cached-copy' @copy_exclude = [] @purge_before_symlink = %w{log tmp/pids public/system} @create_dirs_before_symlink = %w{tmp public config} @symlink_before_migrate = {"config/database.yml" => "config/database.yml"} @symlinks = {"system" => "public/system", "pids" => "tmp/pids", "log" => "log"} @revision = 'HEAD' @action = :deploy @migrate = false @rollback_on_error = false @remote = "origin" @enable_submodules = false @shallow_clone = false @scm_provider = Chef::Provider::Git @svn_force_export = false @provider = Chef::Provider::Deploy::Timestamped @allowed_actions.push(:force_deploy, :deploy, :rollback) @additional_remotes = Hash[] @keep_releases = 5 end # where the checked out/cloned code goes def destination @destination ||= shared_path + "/#{@repository_cache}" end # where shared stuff goes, i.e., logs, tmp, etc. goes here def shared_path @shared_path ||= @deploy_to + "/shared" end # where the deployed version of your code goes def current_path @current_path ||= @deploy_to + "/current" end def depth @shallow_clone ? "5" : nil end # note: deploy_to is your application "meta-root." def deploy_to(arg=nil) set_or_return( :deploy_to, arg, :kind_of => [ String ] ) end def repo(arg=nil) set_or_return( :repo, arg, :kind_of => [ String ] ) end alias :repository :repo def remote(arg=nil) set_or_return( :remote, arg, :kind_of => [ String ] ) end def role(arg=nil) set_or_return( :role, arg, :kind_of => [ String ] ) end def restart_command(arg=nil, &block) arg ||= block set_or_return( :restart_command, arg, :kind_of => [ String, Proc ] ) end alias :restart :restart_command def migrate(arg=nil) set_or_return( :migrate, arg, :kind_of => [ TrueClass, FalseClass ] ) end def migration_command(arg=nil) set_or_return( :migration_command, arg, :kind_of => [ String ] ) end def rollback_on_error(arg=nil) set_or_return( :rollback_on_error, arg, :kind_of => [ TrueClass, FalseClass ] ) end def user(arg=nil) set_or_return( :user, arg, :kind_of => [ String ] ) end def group(arg=nil) set_or_return( :group, arg, :kind_of => [ String ] ) end def enable_submodules(arg=nil) set_or_return( :enable_submodules, arg, :kind_of => [ TrueClass, FalseClass ] ) end def shallow_clone(arg=nil) set_or_return( :shallow_clone, arg, :kind_of => [ TrueClass, FalseClass ] ) end def repository_cache(arg=nil) set_or_return( :repository_cache, arg, :kind_of => [ String ] ) end def copy_exclude(arg=nil) set_or_return( :copy_exclude, arg, :kind_of => [ String ] ) end def revision(arg=nil) set_or_return( :revision, arg, :kind_of => [ String ] ) end alias :branch :revision def git_ssh_wrapper(arg=nil) set_or_return( :git_ssh_wrapper, arg, :kind_of => [ String ] ) end alias :ssh_wrapper :git_ssh_wrapper def svn_username(arg=nil) set_or_return( :svn_username, arg, :kind_of => [ String ] ) end def svn_password(arg=nil) set_or_return( :svn_password, arg, :kind_of => [ String ] ) end def svn_arguments(arg=nil) set_or_return( :svn_arguments, arg, :kind_of => [ String ] ) end def svn_info_args(arg=nil) set_or_return( :svn_arguments, arg, :kind_of => [ String ]) end def scm_provider(arg=nil) klass = if arg.kind_of?(String) || arg.kind_of?(Symbol) lookup_provider_constant(arg) else arg end set_or_return( :scm_provider, klass, :kind_of => [ Class ] ) end def svn_force_export(arg=nil) set_or_return( :svn_force_export, arg, :kind_of => [ TrueClass, FalseClass ] ) end def environment(arg=nil) if arg.is_a?(String) Chef::Log.debug "Setting RAILS_ENV, RACK_ENV, and MERB_ENV to `#{arg}'" Chef::Log.warn "[DEPRECATED] please modify your deploy recipe or attributes to set the environment using a hash" arg = {"RAILS_ENV"=>arg,"MERB_ENV"=>arg,"RACK_ENV"=>arg} end set_or_return( :environment, arg, :kind_of => [ Hash ] ) end # The number of old release directories to keep around after cleanup def keep_releases(arg=nil) [set_or_return( :keep_releases, arg, :kind_of => [ Integer ]), 1].max end # An array of paths, relative to your app's root, to be purged from a # SCM clone/checkout before symlinking. Use this to get rid of files and # directories you want to be shared between releases. # Default: ["log", "tmp/pids", "public/system"] def purge_before_symlink(arg=nil) set_or_return( :purge_before_symlink, arg, :kind_of => Array ) end # An array of paths, relative to your app's root, where you expect dirs to # exist before symlinking. This runs after #purge_before_symlink, so you # can use this to recreate dirs that you had previously purged. # For example, if you plan to use a shared directory for pids, and you # want it to be located in $APP_ROOT/tmp/pids, you could purge tmp, # then specify tmp here so that the tmp directory will exist when you # symlink the pids directory in to the current release. # Default: ["tmp", "public", "config"] def create_dirs_before_symlink(arg=nil) set_or_return( :create_dirs_before_symlink, arg, :kind_of => Array ) end # A Hash of shared/dir/path => release/dir/path. This attribute determines # which files and dirs in the shared directory get symlinked to the current # release directory, and where they go. If you have a directory # $shared/pids that you would like to symlink as $current_release/tmp/pids # you specify it as "pids" => "tmp/pids" # Default {"system" => "public/system", "pids" => "tmp/pids", "log" => "log"} def symlinks(arg=nil) set_or_return( :symlinks, arg, :kind_of => Hash ) end # A Hash of shared/dir/path => release/dir/path. This attribute determines # which files in the shared directory get symlinked to the current release # directory and where they go. Unlike map_shared_files, these are symlinked # *before* any migration is run. # For a rails/merb app, this is used to link in a known good database.yml # (with the production db password) before running migrate. # Default {"config/database.yml" => "config/database.yml"} def symlink_before_migrate(arg=nil) set_or_return( :symlink_before_migrate, arg, :kind_of => Hash ) end # Callback fires before migration is run. def before_migrate(arg=nil, &block) arg ||= block set_or_return(:before_migrate, arg, :kind_of => [Proc, String]) end # Callback fires before symlinking def before_symlink(arg=nil, &block) arg ||= block set_or_return(:before_symlink, arg, :kind_of => [Proc, String]) end # Callback fires before restart def before_restart(arg=nil, &block) arg ||= block set_or_return(:before_restart, arg, :kind_of => [Proc, String]) end # Callback fires after restart def after_restart(arg=nil, &block) arg ||= block set_or_return(:after_restart, arg, :kind_of => [Proc, String]) end def additional_remotes(arg=nil) set_or_return( :additional_remotes, arg, :kind_of => Hash ) end # FIXME The Deploy resource may be passed to an SCM provider as its # resource. The SCM provider knows that SCM resources can specify a # timeout for SCM operations. The deploy resource must therefore support # a timeout method, but the timeout it describes is for SCM operations, # not the overall deployment. This is potentially confusing. def timeout(arg=nil) set_or_return( :timeout, arg, :kind_of => Integer ) end end end end chef-11.8.2/lib/chef/resource/route.rb0000644000004100000410000000556512254362222017540 0ustar www-datawww-data# # Author:: Bryan McLellan (btm@loftninjas.org) # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2009 Bryan McLellan # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource' class Chef class Resource class Route < Chef::Resource identity_attr :target state_attrs :netmask, :gateway def initialize(name, run_context=nil) super @resource_name = :route @target = name @action = [:add] @allowed_actions.push(:add, :delete) @netmask = nil @gateway = nil @metric = nil @device = nil @route_type = :host @networking = nil @networking_ipv6 = nil @hostname = nil @domainname = nil @domain = nil end def networking(arg=nil) set_or_return( :networking, arg, :kind_of => String ) end def networking_ipv6(arg=nil) set_or_return( :networking_ipv6, arg, :kind_of => String ) end def hostname(arg=nil) set_or_return( :hostname, arg, :kind_of => String ) end def domainname(arg=nil) set_or_return( :domainname, arg, :kind_of => String ) end def domain(arg=nil) set_or_return( :domain, arg, :kind_of => String ) end def target(arg=nil) set_or_return( :target, arg, :kind_of => String ) end def netmask(arg=nil) set_or_return( :netmask, arg, :kind_of => String ) end def gateway(arg=nil) set_or_return( :gateway, arg, :kind_of => String ) end def metric(arg=nil) set_or_return( :metric, arg, :kind_of => Integer ) end def device(arg=nil) set_or_return( :device, arg, :kind_of => String ) end def route_type(arg=nil) real_arg = arg.kind_of?(String) ? arg.to_sym : arg set_or_return( :route_type, real_arg, :equal_to => [ :host, :net ] ) end end end end chef-11.8.2/lib/chef/resource/service.rb0000644000004100000410000001114112254362222020025 0ustar www-datawww-data# # Author:: AJ Christensen () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource' class Chef class Resource class Service < Chef::Resource identity_attr :service_name state_attrs :enabled, :running def initialize(name, run_context=nil) super @resource_name = :service @service_name = name @enabled = nil @running = nil @parameters = nil @pattern = service_name @start_command = nil @stop_command = nil @status_command = nil @restart_command = nil @reload_command = nil @init_command = nil @priority = nil @action = "nothing" @startup_type = :automatic @supports = { :restart => false, :reload => false, :status => false } @allowed_actions.push(:enable, :disable, :start, :stop, :restart, :reload) end def service_name(arg=nil) set_or_return( :service_name, arg, :kind_of => [ String ] ) end # regex for match against ps -ef when !supports[:has_status] && status == nil def pattern(arg=nil) set_or_return( :pattern, arg, :kind_of => [ String ] ) end # command to call to start service def start_command(arg=nil) set_or_return( :start_command, arg, :kind_of => [ String ] ) end # command to call to stop service def stop_command(arg=nil) set_or_return( :stop_command, arg, :kind_of => [ String ] ) end # command to call to get status of service def status_command(arg=nil) set_or_return( :status_command, arg, :kind_of => [ String ] ) end # command to call to restart service def restart_command(arg=nil) set_or_return( :restart_command, arg, :kind_of => [ String ] ) end def reload_command(arg=nil) set_or_return( :reload_command, arg, :kind_of => [ String ] ) end # The path to the init script associated with the service. On many # distributions this is '/etc/init.d/SERVICE_NAME' by default. In # non-standard configurations setting this value will save having to # specify overrides for the start_command, stop_command and # restart_command attributes. def init_command(arg=nil) set_or_return( :init_command, arg, :kind_of => [ String ] ) end # if the service is enabled or not def enabled(arg=nil) set_or_return( :enabled, arg, :kind_of => [ TrueClass, FalseClass ] ) end # if the service is running or not def running(arg=nil) set_or_return( :running, arg, :kind_of => [ TrueClass, FalseClass ] ) end # Priority arguments can have two forms: # # - a simple number, in which the default start runlevels get # that as the start value and stop runlevels get 100 - value. # # - a hash like { 2 => [:start, 20], 3 => [:stop, 55] }, where # the service will be marked as started with priority 20 in # runlevel 2, stopped in 3 with priority 55 and no symlinks or # similar for other runlevels # def priority(arg=nil) set_or_return(:priority, arg, :kind_of => [ Integer, String, Hash ]) end def parameters(arg=nil) set_or_return( :parameters, arg, :kind_of => [ Hash ] ) end def supports(args={}) if args.is_a? Array args.each { |arg| @supports[arg] = true } elsif args.any? @supports = args else @supports end end end end end chef-11.8.2/lib/chef/resource/conditional_action_not_nothing.rb0000644000004100000410000000223712254362222024641 0ustar www-datawww-data# # Author:: Xabier de Zuazo () # Copyright:: Copyright (c) 2013 Onddo Labs, SL. # License:: Apache License, Version 2.0 # # 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. # class Chef class Resource class ConditionalActionNotNothing attr_reader :current_action def initialize(current_action) @current_action = current_action end def continue? # @positivity == not_if @current_action != :nothing end def short_description description end def description "action :nothing" end def to_text "not_if { action == :nothing }" end end end end chef-11.8.2/lib/chef/resource/template.rb0000644000004100000410000001720112254362222020203 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Seth Chisamore () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2008, 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/file' require 'chef/provider/template' require 'chef/mixin/securable' class Chef class Resource class Template < Chef::Resource::File include Chef::Mixin::Securable provides :template, :on_platforms => :all attr_reader :inline_helper_blocks attr_reader :inline_helper_modules def initialize(name, run_context=nil) super @resource_name = :template @action = "create" @source = "#{::File.basename(name)}.erb" @cookbook = nil @local = false @variables = Hash.new @provider = Chef::Provider::Template @inline_helper_blocks = {} @inline_helper_modules = [] @helper_modules = [] end def source(file=nil) set_or_return( :source, file, :kind_of => [ String ] ) end def variables(args=nil) set_or_return( :variables, args, :kind_of => [ Hash ] ) end def cookbook(args=nil) set_or_return( :cookbook, args, :kind_of => [ String ] ) end def local(args=nil) set_or_return( :local, args, :kind_of => [ TrueClass, FalseClass ] ) end # Declares a helper method to be defined in the template context when # rendering. # # === Example: # # ==== Basic usage: # Given the following helper: # helper(:static_value) { "hello from helper" } # A template with the following code: # <%= static_value %> # Will render as; # hello from helper # # ==== Referencing Instance Variables: # Any instance variables available to the template can be referenced in # the method body. For example, you can simplify accessing app-specific # node attributes like this: # helper(:app) { @node[:my_app_attributes] } # And use it in a template like this: # <%= app[:listen_ports] %> # This is equivalent to the non-helper template code: # <%= @node[:my_app_attributes][:listen_ports] %> # # ==== Method Arguments: # Helper methods can also take arguments. The syntax available for # argument specification will be dependent on ruby version. Ruby 1.8 only # supports a subset of the argument specification syntax available for # method definition, whereas 1.9 supports the full syntax. # # Continuing the above example of simplifying attribute access, we can # define a helper to look up app-specific attributes like this: # helper(:app) { |setting| @node[:my_app_attributes][setting] } # The template can then look up attributes like this: # <%= app(:listen_ports) %> def helper(method_name, &block) unless block_given? raise Exceptions::ValidationFailed, "`helper(:method)` requires a block argument (e.g., `helper(:method) { code }`)" end unless method_name.kind_of?(Symbol) raise Exceptions::ValidationFailed, "method_name argument to `helper(method_name)` must be a symbol (e.g., `helper(:method) { code }`)" end @inline_helper_blocks[method_name] = block end # Declares a module to define helper methods in the template's context # when rendering. There are two primary forms. # # === Inline Module Definition # When a block is given, the block is used to define a module which is # then mixed in to the template context w/ `extend`. # # ==== Inline Module Example # Given the following code in the template resource: # helpers do # # Add "syntax sugar" for referencing app-specific attributes # def app(attribute) # @node[:my_app_attributes][attribute] # end # end # You can use it in the template like so: # <%= app(:listen_ports) %> # Which is equivalent to: # <%= @node[:my_app_attributes][:listen_ports] %> # # === External Module Form # When a module name is given, the template context will be extended with # that module. This is the recommended way to customize template contexts # when you need to define more than an handful of helper functions (but # also try to keep your template helpers from getting out of hand--if you # have very complex logic in your template helpers, you should further # extract your code into separate libraries). # # ==== External Module Example # To extract the above inline module code to a library, you'd create a # library file like this: # module MyTemplateHelper # # Add "syntax sugar" for referencing app-specific attributes # def app(attribute) # @node[:my_app_attributes][attribute] # end # end # And in the template resource: # helpers(MyTemplateHelper) # The template code in the above example will work unmodified. def helpers(module_name=nil,&block) if block_given? and !module_name.nil? raise Exceptions::ValidationFailed, "Passing both a module and block to #helpers is not supported. Call #helpers multiple times instead" elsif block_given? @inline_helper_modules << block elsif module_name.kind_of?(::Module) @helper_modules << module_name elsif module_name.nil? raise Exceptions::ValidationFailed, "#helpers requires either a module name or inline module code as a block.\n" + "e.g.: helpers do; helper_code; end;\n" + "OR: helpers(MyHelpersModule)" else raise Exceptions::ValidationFailed, "Argument to #helpers must be a module. You gave #{module_name.inspect} (#{module_name.class})" end end # Compiles all helpers from inline method definitions, inline module # definitions, and external modules into an Array of Modules. The context # object for the template is extended with these modules to provide # per-resource template logic. def helper_modules compiled_helper_methods + compiled_helper_modules + @helper_modules end private # compiles helper methods into a module that can be included in template context def compiled_helper_methods if inline_helper_blocks.empty? [] else resource_helper_blocks = inline_helper_blocks helper_mod = Module.new do resource_helper_blocks.each do |method_name, method_body| define_method(method_name, &method_body) end end [ helper_mod ] end end def compiled_helper_modules @inline_helper_modules.map do |module_body| Module.new(&module_body) end end end end end chef-11.8.2/lib/chef/resource/batch.rb0000644000004100000410000000163712254362222017457 0ustar www-datawww-data# # Author:: Adam Edwards () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/windows_script' class Chef class Resource class Batch < Chef::Resource::WindowsScript def initialize(name, run_context=nil) super(name, run_context, :batch, "cmd.exe") end end end end chef-11.8.2/lib/chef/resource/csh.rb0000644000004100000410000000163712254362222017153 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/script' class Chef class Resource class Csh < Chef::Resource::Script def initialize(name, run_context=nil) super @resource_name = :csh @interpreter = "csh" end end end end chef-11.8.2/lib/chef/run_lock.rb0000644000004100000410000001061112254362222016353 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'chef/mixin/create_path' require 'fcntl' if Chef::Platform.windows? require 'chef/win32/mutex' end class Chef # == Chef::RunLock # Provides an interface for acquiring and releasing a system-wide exclusive # lock. # # Used by Chef::Client to ensure only one instance of chef-client (or solo) # is modifying the system at a time. class RunLock include Chef::Mixin::CreatePath attr_reader :runlock attr_reader :mutex attr_reader :runlock_file # Create a new instance of RunLock # === Arguments # * :lockfile::: the full path to the lockfile. def initialize(lockfile) @runlock_file = lockfile @runlock = nil @mutex = nil end # Acquire the system-wide lock. Will block indefinitely if another process # already has the lock. # # Each call to acquire should have a corresponding call to #release. # # The implementation is based on File#flock (see also: flock(2)). # # Either acquire() or test() methods should be called in order to # get the ownership of run_lock. def acquire wait unless test end # # Tests and if successful acquires the system-wide lock. # Returns true if the lock is acquired, false otherwise. # # Either acquire() or test() methods should be called in order to # get the ownership of run_lock. def test # ensure the runlock_file path exists create_path(File.dirname(runlock_file)) @runlock = File.open(runlock_file,'a+') if Chef::Platform.windows? acquire_win32_mutex else # If we support FD_CLOEXEC, then use it. # NB: ruby-2.0.0-p195 sets FD_CLOEXEC by default, but not # ruby-1.8.7/1.9.3 if Fcntl.const_defined?('F_SETFD') && Fcntl.const_defined?('FD_CLOEXEC') runlock.fcntl(Fcntl::F_SETFD, runlock.fcntl(Fcntl::F_GETFD, 0) | Fcntl::FD_CLOEXEC) end # Flock will return 0 if it can acquire the lock otherwise it # will return false if runlock.flock(File::LOCK_NB|File::LOCK_EX) == 0 true else false end end end # # Waits until acquiring the system-wide lock. # def wait runpid = runlock.read.strip.chomp Chef::Log.warn("Chef client #{runpid} is running, will wait for it to finish and then run.") if Chef::Platform.windows? mutex.wait else runlock.flock(File::LOCK_EX) end end def save_pid runlock.truncate(0) runlock.rewind # truncate doesn't reset position to 0. runlock.write(Process.pid.to_s) # flush the file fsync flushes the system buffers # in addition to ruby buffers runlock.fsync end # Release the system-wide lock. def release if runlock if Chef::Platform.windows? mutex.release else runlock.flock(File::LOCK_UN) end runlock.close # Don't unlink the pid file, if another chef-client was waiting, it # won't be recreated. Better to leave a "dead" pid file than not have # it available if you need to break the lock. reset end end private def reset @runlock = nil @mutex = nil end # Since flock mechanism doesn't exist on windows we are using # platform Mutex. # We are creating a "Global" mutex here so that non-admin # users can not DoS chef-client by creating the same named # mutex we are using locally. # Mutex name is case-sensitive contrary to other things in # windows. "\" is the only invalid character. def acquire_win32_mutex @mutex = Chef::ReservedNames::Win32::Mutex.new("Global\\#{runlock_file.gsub(/[\\]/, "/").downcase}") mutex.test end end end chef-11.8.2/lib/chef/cookbook_site_streaming_uploader.rb0000644000004100000410000002112012254362222023332 0ustar www-datawww-data# # Author:: Stanislav Vitvitskiy # Author:: Nuo Yan (nuo@opscode.com) # Author:: Christopher Walters () # Copyright:: Copyright (c) 2009, 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'net/http' require 'mixlib/authentication/signedheaderauth' require 'openssl' class Chef # == Chef::CookbookSiteStreamingUploader # A streaming multipart HTTP upload implementation. Used to upload cookbooks # (in tarball form) to http://cookbooks.opscode.com # # inspired by http://stanislavvitvitskiy.blogspot.com/2008/12/multipart-post-in-ruby.html class CookbookSiteStreamingUploader DefaultHeaders = { 'accept' => 'application/json', 'x-chef-version' => ::Chef::VERSION } class << self def create_build_dir(cookbook) tmp_cookbook_path = Tempfile.new("chef-#{cookbook.name}-build") tmp_cookbook_path.close tmp_cookbook_dir = tmp_cookbook_path.path File.unlink(tmp_cookbook_dir) FileUtils.mkdir_p(tmp_cookbook_dir) Chef::Log.debug("Staging at #{tmp_cookbook_dir}") checksums_to_on_disk_paths = cookbook.checksums Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |segment| cookbook.manifest[segment].each do |manifest_record| path_in_cookbook = manifest_record[:path] on_disk_path = checksums_to_on_disk_paths[manifest_record[:checksum]] dest = File.join(tmp_cookbook_dir, cookbook.name.to_s, path_in_cookbook) FileUtils.mkdir_p(File.dirname(dest)) Chef::Log.debug("Staging #{on_disk_path} to #{dest}") FileUtils.cp(on_disk_path, dest) end end # First, generate metadata Chef::Log.debug("Generating metadata") kcm = Chef::Knife::CookbookMetadata.new kcm.config[:cookbook_path] = [ tmp_cookbook_dir ] kcm.name_args = [ cookbook.name.to_s ] kcm.run tmp_cookbook_dir end def post(to_url, user_id, secret_key_filename, params = {}, headers = {}) make_request(:post, to_url, user_id, secret_key_filename, params, headers) end def put(to_url, user_id, secret_key_filename, params = {}, headers = {}) make_request(:put, to_url, user_id, secret_key_filename, params, headers) end def make_request(http_verb, to_url, user_id, secret_key_filename, params = {}, headers = {}) boundary = '----RubyMultipartClient' + rand(1000000).to_s + 'ZZZZZ' parts = [] content_file = nil timestamp = Time.now.utc.iso8601 secret_key = OpenSSL::PKey::RSA.new(File.read(secret_key_filename)) unless params.nil? || params.empty? params.each do |key, value| if value.kind_of?(File) content_file = value filepath = value.path filename = File.basename(filepath) parts << StringPart.new( "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"" + key.to_s + "\"; filename=\"" + filename + "\"\r\n" + "Content-Type: application/octet-stream\r\n\r\n") parts << StreamPart.new(value, File.size(filepath)) parts << StringPart.new("\r\n") else parts << StringPart.new( "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"" + key.to_s + "\"\r\n\r\n") parts << StringPart.new(value.to_s + "\r\n") end end parts << StringPart.new("--" + boundary + "--\r\n") end body_stream = MultipartStream.new(parts) timestamp = Time.now.utc.iso8601 url = URI.parse(to_url) Chef::Log.logger.debug("Signing: method: #{http_verb}, path: #{url.path}, file: #{content_file}, User-id: #{user_id}, Timestamp: #{timestamp}") # We use the body for signing the request if the file parameter # wasn't a valid file or wasn't included. Extract the body (with # multi-part delimiters intact) to sign the request. # TODO: tim: 2009-12-28: It'd be nice to remove this special case, and # always hash the entire request body. In the file case it would just be # expanded multipart text - the entire body of the POST. content_body = parts.inject("") { |result,part| result + part.read(0, part.size) } content_file.rewind if content_file # we consumed the file for the above operation, so rewind it. signing_options = { :http_method=>http_verb, :path=>url.path, :user_id=>user_id, :timestamp=>timestamp} (content_file && signing_options[:file] = content_file) || (signing_options[:body] = (content_body || "")) headers.merge!(Mixlib::Authentication::SignedHeaderAuth.signing_object(signing_options).sign(secret_key)) content_file.rewind if content_file # net/http doesn't like symbols for header keys, so we'll to_s each one just in case headers = DefaultHeaders.merge(Hash[*headers.map{ |k,v| [k.to_s, v] }.flatten]) req = case http_verb when :put Net::HTTP::Put.new(url.path, headers) when :post Net::HTTP::Post.new(url.path, headers) end req.content_length = body_stream.size req.content_type = 'multipart/form-data; boundary=' + boundary unless parts.empty? req.body_stream = body_stream http = Net::HTTP.new(url.host, url.port) if url.scheme == "https" http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE end res = http.request(req) #res = http.start {|http_proc| http_proc.request(req) } # alias status to code and to_s to body for test purposes # TODO: stop the following madness! class << res alias :to_s :body # BUGBUG this makes the response compatible with what respsonse_steps expects to test headers (response.headers[] -> response[]) def headers self end def status code.to_i end end res end end class StreamPart def initialize(stream, size) @stream, @size = stream, size end def size @size end # read the specified amount from the stream def read(offset, how_much) @stream.read(how_much) end end class StringPart def initialize(str) @str = str end def size @str.length end # read the specified amount from the string startiung at the offset def read(offset, how_much) @str[offset, how_much] end end class MultipartStream def initialize(parts) @parts = parts @part_no = 0 @part_offset = 0 end def size @parts.inject(0) {|size, part| size + part.size} end def read(how_much, dst_buf = nil) if @part_no >= @parts.size dst_buf.replace('') if dst_buf return dst_buf end how_much_current_part = @parts[@part_no].size - @part_offset how_much_current_part = if how_much_current_part > how_much how_much else how_much_current_part end how_much_next_part = how_much - how_much_current_part current_part = @parts[@part_no].read(@part_offset, how_much_current_part) # recurse into the next part if the current one was not large enough if how_much_next_part > 0 @part_no += 1 @part_offset = 0 next_part = read(how_much_next_part) result = current_part + if next_part next_part else '' end else @part_offset += how_much_current_part result = current_part end dst_buf ? dst_buf.replace(result || '') : result end end end end chef-11.8.2/lib/chef/resource_collection/0000755000004100000410000000000012254362222020255 5ustar www-datawww-datachef-11.8.2/lib/chef/resource_collection/stepable_iterator.rb0000644000004100000410000000530212254362222024312 0ustar www-datawww-data# Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 Daniel DeLeo # License:: Apache License, Version 2.0 # # 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. # class Chef class ResourceCollection class StepableIterator def self.for_collection(new_collection) instance = new(new_collection) instance end attr_accessor :collection attr_reader :position def initialize(collection=[]) @position = 0 @paused = false @collection = collection end def size collection.size end def each(&block) reset_iteration(block) @iterator_type = :element iterate end def each_index(&block) reset_iteration(block) @iterator_type = :index iterate end def each_with_index(&block) reset_iteration(block) @iterator_type = :element_with_index iterate end def paused? @paused end def pause @paused = true end def resume @paused = false iterate end def rewind @position = 0 end def skip_back(skips=1) @position -= skips end def skip_forward(skips=1) @position += skips end def step return nil if @position == size call_iterator_block @position += 1 end def iterate_on(iteration_type, &block) @iterator_type = iteration_type @iterator_block = block end private def reset_iteration(iterator_block) @iterator_block = iterator_block @position = 0 @paused = false end def iterate while @position < size && !paused? step end collection end def call_iterator_block case @iterator_type when :element @iterator_block.call(collection[@position]) when :index @iterator_block.call(@position) when :element_with_index @iterator_block.call(collection[@position], @position) else raise "42error: someone forgot to set @iterator_type, wtf?" end end end end end chef-11.8.2/lib/chef/application/0000755000004100000410000000000012254362222016516 5ustar www-datawww-datachef-11.8.2/lib/chef/application/windows_service_manager.rb0000644000004100000410000001467212254362222023761 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'win32/service' require 'chef/config' require 'mixlib/cli' class Chef class Application # # This class is used to create and manage a windows service. # Service should be created using Daemon class from # win32/service gem. # For an example see: Chef::Application::WindowsService # # Outside programs are expected to use this class to manage # windows services. # class WindowsServiceManager include Mixlib::CLI option :action, :short => "-a ACTION", :long => "--action ACTION", :default => "status", :description => "Action to carry out on chef-service (install, uninstall, status, start, stop, pause, or resume)" option :config_file, :short => "-c CONFIG", :long => "--config CONFIG", :default => "#{ENV['SYSTEMDRIVE']}/chef/client.rb", :description => "The configuration file to use for chef runs" option :log_location, :short => "-L LOGLOCATION", :long => "--logfile LOGLOCATION", :description => "Set the log file location for chef-service", :default => "#{ENV['SYSTEMDRIVE']}/chef/client.log" option :help, :short => "-h", :long => "--help", :description => "Show this message", :on => :tail, :boolean => true, :show_options => true, :exit => 0 option :version, :short => "-v", :long => "--version", :description => "Show chef version", :boolean => true, :proc => lambda {|v| puts "Chef: #{::Chef::VERSION}"}, :exit => 0 def initialize(service_options) # having to call super in initialize is the most annoying # anti-pattern :( super() raise ArgumentError, "Service definition is not provided" if service_options.nil? required_options = [:service_name, :service_display_name, :service_name, :service_description, :service_file_path] required_options.each do |req_option| if !service_options.has_key?(req_option) raise ArgumentError, "Service definition doesn't contain required option #{req_option}" end end @service_name = service_options[:service_name] @service_display_name = service_options[:service_display_name] @service_description = service_options[:service_description] @service_file_path = service_options[:service_file_path] end def run(params = ARGV) parse_options(params) case config[:action] when 'install' if service_exists? puts "Service #{@service_name} already exists on the system." else ruby = File.join(RbConfig::CONFIG['bindir'], 'ruby') opts = "" opts << " -c #{config[:config_file]}" if config[:config_file] opts << " -L #{config[:log_location]}" if config[:log_location] # Quote the full paths to deal with possible spaces in the path name. # Also ensure all forward slashes are backslashes cmd = "\"#{ruby}\" \"#{@service_file_path}\" #{opts}".gsub(File::SEPARATOR, File::ALT_SEPARATOR) ::Win32::Service.new( :service_name => @service_name, :display_name => @service_display_name, :description => @service_description, :start_type => ::Win32::Service::SERVICE_AUTO_START, :binary_path_name => cmd ) puts "Service '#{@service_name}' has successfully been installed." end when 'status' if !service_exists? puts "Service #{@service_name} doesn't exist on the system." else puts "State of #{@service_name} service is: #{current_state}" end when 'start' # TODO: allow override of startup parameters here? take_action('start', RUNNING) when 'stop' take_action('stop', STOPPED) when 'uninstall', 'delete' take_action('stop', STOPPED) unless service_exists? puts "Service #{@service_name} doesn't exist on the system." else ::Win32::Service.delete(@service_name) puts "Service #{@service_name} deleted" end when 'pause' take_action('pause', PAUSED) when 'resume' take_action('resume', RUNNING) end end private # Just some state constants STOPPED = "stopped" RUNNING = "running" PAUSED = "paused" def service_exists? return ::Win32::Service.exists?(@service_name) end def take_action(action=nil, desired_state=nil) if service_exists? if current_state != desired_state ::Win32::Service.send(action, @service_name) wait_for_state(desired_state) puts "Service '#{@service_name}' is now '#{current_state}'." else puts "Service '#{@service_name}' is already '#{desired_state}'." end else puts "Cannot '#{action}' service '#{@service_name}'" puts "Service #{@service_name} doesn't exist on the system." end end def current_state ::Win32::Service.status(@service_name).current_state end # Helper method that waits for a status to change its state since state # changes aren't usually instantaneous. def wait_for_state(desired_state) while current_state != desired_state puts "One moment... #{current_state}" sleep 1 end end end end end chef-11.8.2/lib/chef/application/client.rb0000644000004100000410000002452212254362222020326 0ustar www-datawww-data# # Author:: AJ Christensen () # Author:: Mark Mzyk (mmzyk@opscode.com) # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'chef/application' require 'chef/client' require 'chef/config' require 'chef/daemon' require 'chef/log' require 'chef/config_fetcher' require 'chef/handler/error_report' class Chef::Application::Client < Chef::Application # Mimic self_pipe sleep from Unicorn to capture signals safely SELF_PIPE = [] option :config_file, :short => "-c CONFIG", :long => "--config CONFIG", :description => "The configuration file to use" option :formatter, :short => "-F FORMATTER", :long => "--format FORMATTER", :description => "output format to use", :proc => lambda { |format| Chef::Config.add_formatter(format) } option :force_logger, :long => "--force-logger", :description => "Use logger output instead of formatter output", :boolean => true, :default => false option :force_formatter, :long => "--force-formatter", :description => "Use formatter output instead of logger output", :boolean => true, :default => false option :color, :long => '--[no-]color', :boolean => true, :default => !Chef::Platform.windows?, :description => "Use colored output, defaults to false on Windows, true otherwise" option :log_level, :short => "-l LEVEL", :long => "--log_level LEVEL", :description => "Set the log level (debug, info, warn, error, fatal)", :proc => lambda { |l| l.to_sym } option :log_location, :short => "-L LOGLOCATION", :long => "--logfile LOGLOCATION", :description => "Set the log file location, defaults to STDOUT - recommended for daemonizing", :proc => nil option :help, :short => "-h", :long => "--help", :description => "Show this message", :on => :tail, :boolean => true, :show_options => true, :exit => 0 option :user, :short => "-u USER", :long => "--user USER", :description => "User to set privilege to", :proc => nil option :group, :short => "-g GROUP", :long => "--group GROUP", :description => "Group to set privilege to", :proc => nil unless Chef::Platform.windows? option :daemonize, :short => "-d", :long => "--daemonize", :description => "Daemonize the process", :proc => lambda { |p| true } end option :pid_file, :short => "-P PID_FILE", :long => "--pid PIDFILE", :description => "Set the PID file location, defaults to /tmp/chef-client.pid", :proc => nil option :interval, :short => "-i SECONDS", :long => "--interval SECONDS", :description => "Run chef-client periodically, in seconds", :proc => lambda { |s| s.to_i } option :once, :long => "--once", :description => "Cancel any interval or splay options, run chef once and exit", :boolean => true option :json_attribs, :short => "-j JSON_ATTRIBS", :long => "--json-attributes JSON_ATTRIBS", :description => "Load attributes from a JSON file or URL", :proc => nil option :node_name, :short => "-N NODE_NAME", :long => "--node-name NODE_NAME", :description => "The node name for this client", :proc => nil option :splay, :short => "-s SECONDS", :long => "--splay SECONDS", :description => "The splay time for running at intervals, in seconds", :proc => lambda { |s| s.to_i } option :chef_server_url, :short => "-S CHEFSERVERURL", :long => "--server CHEFSERVERURL", :description => "The chef server URL", :proc => nil option :validation_key, :short => "-K KEY_FILE", :long => "--validation_key KEY_FILE", :description => "Set the validation key file location, used for registering new clients", :proc => nil option :client_key, :short => "-k KEY_FILE", :long => "--client_key KEY_FILE", :description => "Set the client key file location", :proc => nil option :environment, :short => '-E ENVIRONMENT', :long => '--environment ENVIRONMENT', :description => 'Set the Chef Environment on the node' option :version, :short => "-v", :long => "--version", :description => "Show chef version", :boolean => true, :proc => lambda {|v| puts "Chef: #{::Chef::VERSION}"}, :exit => 0 option :override_runlist, :short => "-o RunlistItem,RunlistItem...", :long => "--override-runlist RunlistItem,RunlistItem...", :description => "Replace current run list with specified items", :proc => lambda{|items| items = items.split(',') items.compact.map{|item| Chef::RunList::RunListItem.new(item) } } option :why_run, :short => '-W', :long => '--why-run', :description => 'Enable whyrun mode', :boolean => true option :client_fork, :short => "-f", :long => "--[no-]fork", :description => "Fork client", :boolean => true option :enable_reporting, :short => "-R", :long => "--enable-reporting", :description => "Enable reporting data collection for chef runs", :boolean => true option :local_mode, :short => "-z", :long => "--local-mode", :description => "Point chef-client at local repository", :boolean => true option :chef_zero_port, :long => "--chef-zero-port PORT", :description => "Port to start chef-zero on" option :config_file_jail, :long => "--config-file-jail PATH", :description => "Directory under which config files are allowed to be loaded (no client.rb or knife.rb outside this path will be loaded)." if Chef::Platform.windows? option :fatal_windows_admin_check, :short => "-A", :long => "--fatal-windows-admin-check", :description => "Fail the run when chef-client doesn't have administrator privileges on Windows", :boolean => true end attr_reader :chef_client_json def initialize super @exit_gracefully = false end # Reconfigure the chef client # Re-open the JSON attributes and load them into the node def reconfigure super Chef::Config[:chef_server_url] = config[:chef_server_url] if config.has_key? :chef_server_url Chef::Config.local_mode = config[:local_mode] if config.has_key?(:local_mode) if Chef::Config.local_mode && !Chef::Config.has_key?(:cookbook_path) && !Chef::Config.has_key?(:chef_repo_path) Chef::Config.chef_repo_path = Chef::Config.find_chef_repo_path(Dir.pwd) end Chef::Config.chef_zero.port = config[:chef_zero_port] if config[:chef_zero_port] if Chef::Config[:daemonize] Chef::Config[:interval] ||= 1800 end if Chef::Config[:once] Chef::Config[:interval] = nil Chef::Config[:splay] = nil end if Chef::Config[:json_attribs] config_fetcher = Chef::ConfigFetcher.new(Chef::Config[:json_attribs]) @chef_client_json = config_fetcher.fetch_json end end def load_config_file Chef::Config.config_file_jail = config[:config_file_jail] if config[:config_file_jail] if !config.has_key?(:config_file) if config[:local_mode] require 'chef/knife' config[:config_file] = Chef::Knife.locate_config_file else config[:config_file] = Chef::Config.platform_specific_path("/etc/chef/client.rb") end end super end def configure_logging super Mixlib::Authentication::Log.use_log_devices( Chef::Log ) Ohai::Log.use_log_devices( Chef::Log ) end def setup_application Chef::Daemon.change_privilege end # Run the chef client, optionally daemonizing or looping at intervals. def run_application unless Chef::Platform.windows? SELF_PIPE.replace IO.pipe trap("USR1") do Chef::Log.info("SIGUSR1 received, waking up") SELF_PIPE[1].putc('.') # wakeup master process from select end trap("TERM") do Chef::Log.info("SIGTERM received, exiting gracefully") @exit_gracefully = true SELF_PIPE[1].putc('.') end end if Chef::Config[:version] puts "Chef version: #{::Chef::VERSION}" end if Chef::Config[:daemonize] Chef::Daemon.daemonize("chef-client") end loop do begin Chef::Application.exit!("Exiting", 0) if @exit_gracefully if Chef::Config[:splay] splay = rand Chef::Config[:splay] Chef::Log.debug("Splay sleep #{splay} seconds") sleep splay end run_chef_client if Chef::Config[:interval] Chef::Log.debug("Sleeping for #{Chef::Config[:interval]} seconds") unless SELF_PIPE.empty? client_sleep Chef::Config[:interval] else # Windows sleep Chef::Config[:interval] end else Chef::Application.exit! "Exiting", 0 end rescue SystemExit => e raise rescue Exception => e if Chef::Config[:interval] Chef::Log.error("#{e.class}: #{e}") Chef::Log.error("Sleeping for #{Chef::Config[:interval]} seconds before trying again") unless SELF_PIPE.empty? client_sleep Chef::Config[:interval] else # Windows sleep Chef::Config[:interval] end retry else Chef::Application.fatal!("#{e.class}: #{e.message}", 1) end end end end private def client_sleep(sec) IO.select([ SELF_PIPE[0] ], nil, nil, sec) or return SELF_PIPE[0].getc end end chef-11.8.2/lib/chef/application/agent.rb0000644000004100000410000000130512254362222020140 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'chef/application' chef-11.8.2/lib/chef/application/knife.rb0000644000004100000410000001166712254362222020152 0ustar www-datawww-data# # Author:: Adam Jacob ( "-c CONFIG", :long => "--config CONFIG", :description => "The configuration file to use", :proc => lambda { |path| File.expand_path(path, Dir.pwd) } verbosity_level = 0 option :verbosity, :short => '-V', :long => '--verbose', :description => "More verbose output. Use twice for max verbosity", :proc => Proc.new { verbosity_level += 1}, :default => 0 option :color, :long => '--[no-]color', :boolean => true, :default => !Chef::Platform.windows?, :description => "Use colored output, defaults to false on Windows, true otherwise" option :environment, :short => "-E ENVIRONMENT", :long => "--environment ENVIRONMENT", :description => "Set the Chef environment" option :editor, :short => "-e EDITOR", :long => "--editor EDITOR", :description => "Set the editor to use for interactive commands", :default => ENV['EDITOR'] option :disable_editing, :short => "-d", :long => "--disable-editing", :description => "Do not open EDITOR, just accept the data as is", :boolean => true, :defaut => false option :help, :short => "-h", :long => "--help", :description => "Show this message", :on => :tail, :boolean => true option :node_name, :short => "-u USER", :long => "--user USER", :description => "API Client Username" option :client_key, :short => "-k KEY", :long => "--key KEY", :description => "API Client Key", :proc => lambda { |path| File.expand_path(path, Dir.pwd) } option :chef_server_url, :short => "-s URL", :long => "--server-url URL", :description => "Chef Server URL" option :yes, :short => "-y", :long => "--yes", :description => "Say yes to all prompts for confirmation" option :defaults, :long => "--defaults", :description => "Accept default values for all questions" option :print_after, :long => "--print-after", :description => "Show the data after a destructive operation" option :format, :short => "-F FORMAT", :long => "--format FORMAT", :description => "Which format to use for output", :default => "summary" option :local_mode, :short => "-z", :long => "--local-mode", :description => "Point knife commands at local repository instead of server", :boolean => true option :chef_zero_port, :long => "--chef-zero-port PORT", :description => "Port to start chef-zero on" option :version, :short => "-v", :long => "--version", :description => "Show chef version", :boolean => true, :proc => lambda {|v| puts "Chef: #{::Chef::VERSION}"}, :exit => 0 # Run knife def run Mixlib::Log::Formatter.show_time = false validate_and_parse_options quiet_traps Chef::Knife.run(ARGV, options) exit 0 end private def quiet_traps trap("TERM") do exit 1 end trap("INT") do exit 2 end end def validate_and_parse_options # Checking ARGV validity *before* parse_options because parse_options # mangles ARGV in some situations if no_command_given? print_help_and_exit(1, NO_COMMAND_GIVEN) elsif no_subcommand_given? if (want_help? || want_version?) print_help_and_exit else print_help_and_exit(2, NO_COMMAND_GIVEN) end end end def no_subcommand_given? ARGV[0] =~ /^-/ end def no_command_given? ARGV.empty? end def want_help? ARGV[0] =~ /^(--help|-h)$/ end def want_version? ARGV[0] =~ /^(--version|-v)$/ end def print_help_and_exit(exitcode=1, fatal_message=nil) Chef::Log.error(fatal_message) if fatal_message begin self.parse_options rescue OptionParser::InvalidOption => e puts "#{e}\n" end puts self.opt_parser puts Chef::Knife.list_commands exit exitcode end end chef-11.8.2/lib/chef/application/solo.rb0000644000004100000410000001604012254362222020020 0ustar www-datawww-data# # Author:: AJ Christensen () # Author:: Mark Mzyk (mmzyk@opscode.com) # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'chef' require 'chef/application' require 'chef/client' require 'chef/config' require 'chef/daemon' require 'chef/log' require 'chef/rest' require 'chef/config_fetcher' require 'fileutils' class Chef::Application::Solo < Chef::Application option :config_file, :short => "-c CONFIG", :long => "--config CONFIG", :default => Chef::Config.platform_specific_path('/etc/chef/solo.rb'), :description => "The configuration file to use" option :formatter, :short => "-F FORMATTER", :long => "--format FORMATTER", :description => "output format to use", :proc => lambda { |format| Chef::Config.add_formatter(format) } option :force_logger, :long => "--force-logger", :description => "Use logger output instead of formatter output", :boolean => true, :default => false option :force_formatter, :long => "--force-formatter", :description => "Use formatter output instead of logger output", :boolean => true, :default => false option :color, :long => '--[no-]color', :boolean => true, :default => true, :description => "Use colored output, defaults to enabled" option :log_level, :short => "-l LEVEL", :long => "--log_level LEVEL", :description => "Set the log level (debug, info, warn, error, fatal)", :proc => lambda { |l| l.to_sym } option :log_location, :short => "-L LOGLOCATION", :long => "--logfile LOGLOCATION", :description => "Set the log file location, defaults to STDOUT", :proc => nil option :help, :short => "-h", :long => "--help", :description => "Show this message", :on => :tail, :boolean => true, :show_options => true, :exit => 0 option :user, :short => "-u USER", :long => "--user USER", :description => "User to set privilege to", :proc => nil option :group, :short => "-g GROUP", :long => "--group GROUP", :description => "Group to set privilege to", :proc => nil unless Chef::Platform.windows? option :daemonize, :short => "-d", :long => "--daemonize", :description => "Daemonize the process", :proc => lambda { |p| true } end option :interval, :short => "-i SECONDS", :long => "--interval SECONDS", :description => "Run chef-client periodically, in seconds", :proc => lambda { |s| s.to_i } option :json_attribs, :short => "-j JSON_ATTRIBS", :long => "--json-attributes JSON_ATTRIBS", :description => "Load attributes from a JSON file or URL", :proc => nil option :node_name, :short => "-N NODE_NAME", :long => "--node-name NODE_NAME", :description => "The node name for this client", :proc => nil option :splay, :short => "-s SECONDS", :long => "--splay SECONDS", :description => "The splay time for running at intervals, in seconds", :proc => lambda { |s| s.to_i } option :recipe_url, :short => "-r RECIPE_URL", :long => "--recipe-url RECIPE_URL", :description => "Pull down a remote gzipped tarball of recipes and untar it to the cookbook cache.", :proc => nil option :version, :short => "-v", :long => "--version", :description => "Show chef version", :boolean => true, :proc => lambda {|v| puts "Chef: #{::Chef::VERSION}"}, :exit => 0 option :override_runlist, :short => "-o RunlistItem,RunlistItem...", :long => "--override-runlist RunlistItem,RunlistItem...", :description => "Replace current run list with specified items", :proc => lambda{|items| items = items.split(',') items.compact.map{|item| Chef::RunList::RunListItem.new(item) } } option :client_fork, :short => "-f", :long => "--[no-]fork", :description => "Fork client", :boolean => true option :why_run, :short => '-W', :long => '--why-run', :description => 'Enable whyrun mode', :boolean => true option :environment, :short => '-E ENVIRONMENT', :long => '--environment ENVIRONMENT', :description => 'Set the Chef Environment on the node' attr_reader :chef_client_json def initialize super end def reconfigure super Chef::Config[:solo] = true if Chef::Config[:daemonize] Chef::Config[:interval] ||= 1800 end if Chef::Config[:json_attribs] config_fetcher = Chef::ConfigFetcher.new(Chef::Config[:json_attribs]) @chef_client_json = config_fetcher.fetch_json end if Chef::Config[:recipe_url] cookbooks_path = Array(Chef::Config[:cookbook_path]).detect{|e| e =~ /\/cookbooks\/*$/ } recipes_path = File.expand_path(File.join(cookbooks_path, '..')) Chef::Log.debug "Creating path #{recipes_path} to extract recipes into" FileUtils.mkdir_p recipes_path path = File.join(recipes_path, 'recipes.tgz') File.open(path, 'wb') do |f| open(Chef::Config[:recipe_url]) do |r| f.write(r.read) end end Chef::Mixin::Command.run_command(:command => "tar zxvf #{path} -C #{recipes_path}") end end def setup_application Chef::Daemon.change_privilege end def run_application if Chef::Config[:daemonize] Chef::Daemon.daemonize("chef-client") end loop do begin if Chef::Config[:splay] splay = rand Chef::Config[:splay] Chef::Log.debug("Splay sleep #{splay} seconds") sleep splay end run_chef_client if Chef::Config[:interval] Chef::Log.debug("Sleeping for #{Chef::Config[:interval]} seconds") sleep Chef::Config[:interval] else Chef::Application.exit! "Exiting", 0 end rescue SystemExit => e raise rescue Exception => e if Chef::Config[:interval] Chef::Log.error("#{e.class}: #{e}") Chef::Log.debug("#{e.class}: #{e}\n#{e.backtrace.join("\n")}") Chef::Log.fatal("Sleeping for #{Chef::Config[:interval]} seconds before trying again") sleep Chef::Config[:interval] retry else Chef::Application.fatal!("#{e.class}: #{e.message}", 1) end end end end end chef-11.8.2/lib/chef/application/windows_service.rb0000644000004100000410000002731012254362222022260 0ustar www-datawww-data# # Author:: Christopher Maier () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef' require 'chef/monologger' require 'chef/application' require 'chef/client' require 'chef/config' require 'chef/handler/error_report' require 'chef/log' require 'chef/rest' require 'mixlib/cli' require 'socket' require 'win32/daemon' require 'chef/mixin/shell_out' class Chef class Application class WindowsService < ::Win32::Daemon include Mixlib::CLI include Chef::Mixin::ShellOut option :config_file, :short => "-c CONFIG", :long => "--config CONFIG", :default => "#{ENV['SYSTEMDRIVE']}/chef/client.rb", :description => "" option :log_location, :short => "-L LOGLOCATION", :long => "--logfile LOGLOCATION", :description => "Set the log file location", :default => "#{ENV['SYSTEMDRIVE']}/chef/client.log" option :splay, :short => "-s SECONDS", :long => "--splay SECONDS", :description => "The splay time for running at intervals, in seconds", :proc => lambda { |s| s.to_i } option :interval, :short => "-i SECONDS", :long => "--interval SECONDS", :description => "Set the number of seconds to wait between chef-client runs", :proc => lambda { |s| s.to_i } def service_init @service_action_mutex = Mutex.new @service_signal = ConditionVariable.new reconfigure Chef::Log.info("Chef Client Service initialized") end def service_main(*startup_parameters) # Chef::Config is initialized during service_init # Set the initial timeout to splay sleep time timeout = rand Chef::Config[:splay] while running? do # Grab the service_action_mutex to make a chef-client run @service_action_mutex.synchronize do begin Chef::Log.info("Next chef-client run will happen in #{timeout} seconds") @service_signal.wait(@service_action_mutex, timeout) # Continue only if service is RUNNING next if state != RUNNING # Reconfigure each time through to pick up any changes in the client file Chef::Log.info("Reconfiguring with startup parameters") reconfigure(startup_parameters) timeout = Chef::Config[:interval] # Honor splay sleep config timeout += rand Chef::Config[:splay] # run chef-client only if service is in RUNNING state next if state != RUNNING Chef::Log.info("Chef-Client service is starting a chef-client run...") run_chef_client rescue SystemExit => e # Do not raise any of the errors here in order to # prevent service crash Chef::Log.error("#{e.class}: #{e}") rescue Exception => e Chef::Log.error("#{e.class}: #{e}") end end end # Daemon class needs to have all the signal callbacks return # before service_main returns. Chef::Log.debug("Giving signal callbacks some time to exit...") sleep 1 Chef::Log.debug("Exiting service...") end ################################################################################ # Control Signal Callback Methods ################################################################################ def service_stop run_warning_displayed = false Chef::Log.info("STOP request from operating system.") loop do # See if a run is in flight if @service_action_mutex.try_lock # Run is not in flight. Wake up service_main to exit. @service_signal.signal @service_action_mutex.unlock break else unless run_warning_displayed Chef::Log.info("Currently a chef run is happening on this system.") Chef::Log.info("Service will stop when run is completed.") run_warning_displayed = true end Chef::Log.debug("Waiting for chef-client run...") sleep 1 end end Chef::Log.info("Service is stopping....") end def service_pause Chef::Log.info("PAUSE request from operating system.") # We don't need to wake up the service_main if it's waiting # since this is a PAUSE signal. if @service_action_mutex.locked? Chef::Log.info("Currently a chef-client run is happening.") Chef::Log.info("Service will pause once it's completed.") else Chef::Log.info("Service is pausing....") end end def service_resume # We don't need to wake up the service_main if it's waiting # since this is a RESUME signal. Chef::Log.info("RESUME signal received from the OS.") Chef::Log.info("Service is resuming....") end def service_shutdown Chef::Log.info("SHUTDOWN signal received from the OS.") # Treat shutdown similar to stop. service_stop end ################################################################################ # Internal Methods ################################################################################ private # Initializes Chef::Client instance and runs it def run_chef_client # The chef client will be started in a new process. We have used shell_out to start the chef-client. # The log_location and config_file of the parent process is passed to the new chef-client process. # We need to add the --no-fork, as by default it is set to fork=true. begin Chef::Log.info "Starting chef-client in a new process" # Pass config params to the new process config_params = " --no-fork" config_params += " -c #{Chef::Config[:config_file]}" unless Chef::Config[:config_file].nil? config_params += " -L #{Chef::Config[:log_location]}" unless Chef::Config[:log_location] == STDOUT # Starts a new process and waits till the process exits result = shell_out("chef-client #{config_params}") Chef::Log.debug "#{result.stdout}" Chef::Log.debug "#{result.stderr}" rescue Mixlib::ShellOut::ShellCommandFailed => e Chef::Log.warn "Not able to start chef-client in new process (#{e})" rescue => e Chef::Log.error e ensure # Once process exits, we log the current process' pid Chef::Log.info "Child process exited (pid: #{Process.pid})" end end def apply_config(config_file_path) Chef::Config.from_file(config_file_path) Chef::Config.merge!(config) end # Lifted from Chef::Application, with addition of optional startup parameters # for playing nicely with Windows Services def reconfigure(startup_parameters=[]) configure_chef startup_parameters configure_logging Chef::Config[:chef_server_url] = config[:chef_server_url] if config.has_key? :chef_server_url unless Chef::Config[:exception_handlers].any? {|h| Chef::Handler::ErrorReport === h} Chef::Config[:exception_handlers] << Chef::Handler::ErrorReport.new end Chef::Config[:interval] ||= 1800 end # Lifted from application.rb # See application.rb for related comments. def configure_logging Chef::Log.init(MonoLogger.new(Chef::Config[:log_location])) if want_additional_logger? configure_stdout_logger end Chef::Log.level = resolve_log_level end def configure_stdout_logger stdout_logger = MonoLogger.new(STDOUT) STDOUT.sync = true stdout_logger.formatter = Chef::Log.logger.formatter Chef::Log.loggers << stdout_logger end # Based on config and whether or not STDOUT is a tty, should we setup a # secondary logger for stdout? def want_additional_logger? ( Chef::Config[:log_location] != STDOUT ) && STDOUT.tty? && (!Chef::Config[:daemonize]) && (Chef::Config[:force_logger]) end # Use of output formatters is assumed if `force_formatter` is set or if # `force_logger` is not set and STDOUT is to a console (tty) def using_output_formatter? Chef::Config[:force_formatter] || (!Chef::Config[:force_logger] && STDOUT.tty?) end def auto_log_level? Chef::Config[:log_level] == :auto end # if log_level is `:auto`, convert it to :warn (when using output formatter) # or :info (no output formatter). See also +using_output_formatter?+ def resolve_log_level if auto_log_level? if using_output_formatter? :warn else :info end else Chef::Config[:log_level] end end def configure_chef(startup_parameters) # Bit of a hack ahead: # It is possible to specify a service's binary_path_name with arguments, like "foo.exe -x argX". # It is also possible to specify startup parameters separately, either via the Services manager # or by using the registry (I think). # In order to accommodate all possible sources of parameterization, we first parse any command line # arguments. We then parse any startup parameters. This works, because Mixlib::CLI reuses its internal # 'config' hash; thus, anything in startup parameters will override any command line parameters that # might be set via the service's binary_path_name # # All these parameters then get layered on top of those from Chef::Config parse_options # Operates on ARGV by default parse_options startup_parameters begin case config[:config_file] when /^(http|https):\/\// Chef::REST.new("", nil, nil).fetch(config[:config_file]) { |f| apply_config(f.path) } else ::File::open(config[:config_file]) { |f| apply_config(f.path) } end rescue Errno::ENOENT => error Chef::Log.warn("*****************************************") Chef::Log.warn("Did not find config file: #{config[:config_file]}, using command line options.") Chef::Log.warn("*****************************************") Chef::Config.merge!(config) rescue SocketError => error Chef::Application.fatal!("Error getting config file #{Chef::Config[:config_file]}", 2) rescue Chef::Exceptions::ConfigurationError => error Chef::Application.fatal!("Error processing config file #{Chef::Config[:config_file]} with error #{error.message}", 2) rescue Exception => error Chef::Application.fatal!("Unknown error processing config file #{Chef::Config[:config_file]} with error #{error.message}", 2) end end end end end # To run this file as a service, it must be called as a script from within # the Windows Service framework. In that case, kick off the main loop! if __FILE__ == $0 Chef::Application::WindowsService.mainloop end chef-11.8.2/lib/chef/application/apply.rb0000644000004100000410000001057412254362222020177 0ustar www-datawww-data# # Author:: Bryan W. Berry () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Bryan W. Berry # Copyright:: Copyright (c) 2012 Daniel DeLeo # License:: Apache License, Version 2.0 # # 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. require 'chef' require 'chef/application' require 'chef/client' require 'chef/config' require 'chef/log' require 'fileutils' require 'tempfile' require 'chef/providers' require 'chef/resources' class Chef::Application::Apply < Chef::Application banner "Usage: chef-apply [RECIPE_FILE] [-e RECIPE_TEXT] [-s]" option :execute, :short => "-e RECIPE_TEXT", :long => "--execute RECIPE_TEXT", :description => "Execute resources supplied in a string", :proc => nil option :stdin, :short => "-s", :long => "--stdin", :description => "Execute resources read from STDIN", :boolean => true option :log_level, :short => "-l LEVEL", :long => "--log_level LEVEL", :description => "Set the log level (debug, info, warn, error, fatal)", :proc => lambda { |l| l.to_sym } option :help, :short => "-h", :long => "--help", :description => "Show this message", :on => :tail, :boolean => true, :show_options => true, :exit => 0 option :version, :short => "-v", :long => "--version", :description => "Show chef version", :boolean => true, :proc => lambda {|v| puts "Chef: #{::Chef::VERSION}"}, :exit => 0 option :why_run, :short => '-W', :long => '--why-run', :description => 'Enable whyrun mode', :boolean => true def initialize super end def reconfigure parse_options Chef::Config.merge!(config) configure_logging end def read_recipe_file(file_name) recipe_path = file_name unless File.exist?(recipe_path) Chef::Application.fatal!("No file exists at #{recipe_path}", 1) end recipe_path = File.expand_path(recipe_path) recipe_fh = open(recipe_path) recipe_text = recipe_fh.read [recipe_text, recipe_fh] end def get_recipe_and_run_context Chef::Config[:solo] = true @chef_client = Chef::Client.new @chef_client.run_ohai @chef_client.load_node @chef_client.build_node run_context = if @chef_client.events.nil? Chef::RunContext.new(@chef_client.node, {}) else Chef::RunContext.new(@chef_client.node, {}, @chef_client.events) end recipe = Chef::Recipe.new("(chef-apply cookbook)", "(chef-apply recipe)", run_context) [recipe, run_context] end # write recipe to temp file, so in case of error, # user gets error w/ context def temp_recipe_file @recipe_fh = Tempfile.open('recipe-temporary-file') @recipe_fh.write(@recipe_text) @recipe_fh.rewind @recipe_filename = @recipe_fh.path end def run_chef_recipe if config[:execute] @recipe_text = config[:execute] temp_recipe_file elsif config[:stdin] @recipe_text = STDIN.read temp_recipe_file else @recipe_filename = ARGV[0] @recipe_text,@recipe_fh = read_recipe_file @recipe_filename end recipe,run_context = get_recipe_and_run_context recipe.instance_eval(@recipe_text, @recipe_filename, 1) runner = Chef::Runner.new(run_context) begin runner.converge ensure @recipe_fh.close end end def run_application begin parse_options run_chef_recipe Chef::Application.exit! "Exiting", 0 rescue SystemExit => e raise rescue Exception => e Chef::Application.debug_stacktrace(e) Chef::Application.fatal!("#{e.class}: #{e.message}", 1) end end # Get this party started def run reconfigure run_application end end chef-11.8.2/lib/chef/monkey_patches/0000755000004100000410000000000012254362222017224 5ustar www-datawww-datachef-11.8.2/lib/chef/monkey_patches/string.rb0000644000004100000410000000247712254362222021071 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # # == String (Patch) # On ruby 1.9, Strings are aware of multibyte characters, so +size+ and +length+ # give the actual number of characters. In Chef::REST, we need the bytesize # so we can correctly set the Content-Length headers, but ruby 1.8.6 and lower # don't define String#bytesize. Monkey patching time! begin require 'enumerator' rescue LoadError end class String unless method_defined?(:bytesize) alias :bytesize :size end unless method_defined?(:lines) def lines enum_for(:each) end end end # <= 1.8.6 needs some ord! class String unless method_defined?(:ord) def ord self.unpack('C').first end end end chef-11.8.2/lib/chef/monkey_patches/net_http.rb0000644000004100000410000000105412254362222021376 0ustar www-datawww-data # Module gets mixed in to Net::HTTP exception classes so we can attach our # RESTRequest object to them and get the request parameters back out later. module ChefNetHTTPExceptionExtensions attr_accessor :chef_rest_request end require 'net/http' module Net class HTTPError include ChefNetHTTPExceptionExtensions end class HTTPRetriableError include ChefNetHTTPExceptionExtensions end class HTTPServerException include ChefNetHTTPExceptionExtensions end class HTTPFatalError include ChefNetHTTPExceptionExtensions end end chef-11.8.2/lib/chef/monkey_patches/object.rb0000644000004100000410000000015612254362222021021 0ustar www-datawww-dataclass Object unless new.respond_to?(:tap) def tap yield self return self end end end chef-11.8.2/lib/chef/monkey_patches/file.rb0000644000004100000410000000150112254362222020465 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # if !File.respond_to?(:realpath) require 'pathname' class File def self.realpath(path) Pathname.new(path).realpath.to_s end end end chef-11.8.2/lib/chef/monkey_patches/net-ssh-multi.rb0000644000004100000410000001161512254362222022266 0ustar www-datawww-data# # Author:: Serdar Sutay () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # # == net-ssh-multi gem patch for concurrency # net-ssh-multi gem has 2 bugs associated with the use of # :concurrent_connections option. # 1-) There is a race condition while fetching the next_session when # :concurrent_connections are set. @open_connections is being # incremented by the connection thread and sometimes # realize_pending_connections!() method can create more than required # connection threads before the @open_connections is set by the # previously created threads. # 2-) When :concurrent_connections is set, server classes are setup # with PendingConnection objects that always return true to busy? # calls. If a connection fails when :concurrent_connections is set, # server ends up returning true to all busy? calls since the session # object is not replaced. Due to this, main event loop (process() # function) never gets terminated. # # See: https://github.com/net-ssh/net-ssh-multi/pull/4 require 'net/ssh/multi/version' if Net::SSH::Multi::Version::STRING == "1.1.0" || Net::SSH::Multi::Version::STRING == "1.2.0" require 'net/ssh/multi' module Net module SSH module Multi class Server # Make sure that server returns false if the ssh connection # has failed. def busy?(include_invisible=false) !failed? && session && session.busy?(include_invisible) end end class Session def next_session(server, force=false) #:nodoc: # don't retry a failed attempt return nil if server.failed? @session_mutex.synchronize do if !force && concurrent_connections && concurrent_connections <= open_connections connection = PendingConnection.new(server) @pending_sessions << connection return connection end # ===== PATCH START # Only increment the open_connections count if the connection # is not being forced. Incase of a force, it will already be # incremented. if !force @open_connections += 1 end # ===== PATCH END end begin server.new_session # I don't understand why this should be necessary--StandardError is a # subclass of Exception, after all--but without explicitly rescuing # StandardError, things like Errno::* and SocketError don't get caught # here! rescue Exception, StandardError => e server.fail! @session_mutex.synchronize { @open_connections -= 1 } case on_error when :ignore then # do nothing when :warn then warn("error connecting to #{server}: #{e.class} (#{e.message})") when Proc then go = catch(:go) { on_error.call(server); nil } case go when nil, :ignore then # nothing when :retry then retry when :raise then raise else warn "unknown 'go' command: #{go.inspect}" end else raise end return nil end end def realize_pending_connections! #:nodoc: return unless concurrent_connections server_list.each do |server| server.close if !server.busy?(true) server.update_session! end @connect_threads.delete_if { |t| !t.alive? } count = concurrent_connections ? (concurrent_connections - open_connections) : @pending_sessions.length count.times do session = @pending_sessions.pop or break # ===== PATCH START # Increment the open_connections count here to prevent # creation of connection thread again before that is # incremented by the thread. @session_mutex.synchronize { @open_connections += 1 } # ===== PATCH END @connect_threads << Thread.new do session.replace_with(next_session(session.server, true)) end end end end end end end end chef-11.8.2/lib/chef/monkey_patches/securerandom.rb0000644000004100000410000000313612254362222022243 0ustar www-datawww-data# # Author:: James Casey # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # # == SecureRandom (Patch) # On ruby 1.9, SecureRandom has a uuid method which generates a v4 UUID. The # backport of SecureRandom to 1.8.7 is missing this method require 'securerandom' module SecureRandom unless respond_to?(:uuid) # SecureRandom.uuid generates a v4 random UUID (Universally Unique IDentifier). # # p SecureRandom.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594" # p SecureRandom.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab" # p SecureRandom.uuid #=> "62936e70-1815-439b-bf89-8492855a7e6b" # # The version 4 UUID is purely random (except the version). # It doesn't contain meaningful information such as MAC address, time, etc. # # See RFC 4122 for details of UUID. def self.uuid ary = self.random_bytes(16).unpack("NnnnnN") ary[2] = (ary[2] & 0x0fff) | 0x4000 ary[3] = (ary[3] & 0x3fff) | 0x8000 "%08x-%04x-%04x-%04x-%04x%08x" % ary end end end chef-11.8.2/lib/chef/monkey_patches/tempfile.rb0000644000004100000410000000417712254362222021367 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # # == Tempfile (Patch) # Tempfile has a horrible bug where it causes an IOError: closed stream in its # finalizer, leading to intermittent application crashes with confusing stack # traces. Here we monkey patch the fix into place. You can track the bug on # ruby's redmine: http://redmine.ruby-lang.org/issues/show/3119 # # The patch is slightly different for Ruby 1.8 and Ruby 1.9, both patches are # included here. class Tempfile # :nodoc: # Tempfile has changes between 1.8.x and 1.9.x # so we monkey patch separately if RUBY_VERSION =~ /^1\.8/ def unlink # keep this order for thread safeness begin File.unlink(@tmpname) if File.exist?(@tmpname) @@cleanlist.delete(@tmpname) @tmpname = nil ObjectSpace.undefine_finalizer(self) rescue Errno::EACCES # may not be able to unlink on Windows; just ignore end end alias delete unlink # There is a patch for this, to be merged into 1.9 at some point. # When that happens, we'll want to also check the RUBY_PATCHLEVEL elsif RUBY_VERSION =~ /^1\.9/ def unlink # keep this order for thread safeness return unless @tmpname begin if File.exist?(@tmpname) File.unlink(@tmpname) end # remove tmpname from remover @data[0] = @data[2] = nil @tmpname = nil rescue Errno::EACCES # may not be able to unlink on Windows; just ignore end end alias delete unlink end end chef-11.8.2/lib/chef/monkey_patches/numeric.rb0000644000004100000410000000042012254362222021207 0ustar www-datawww-dataunless 0.respond_to?(:fdiv) class Numeric def fdiv(other) to_f / other end end end # String elements referenced with [] <= 1.8.6 return a Fixnum. Cheat to allow # for the simpler "test"[2].ord construct class Numeric def ord return self end end chef-11.8.2/lib/chef/monkey_patches/fileutils.rb0000644000004100000410000000350112254362222021550 0ustar www-datawww-data# # Author:: Stephen Delano () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # # == FileUtils::Entry_ (Patch) # On Ruby 1.9.3 and earlier, FileUtils.cp_r(foo, bar, :preserve => true) fails # when attempting to copy a directory containing symlinks. This has been # patched in the trunk of Ruby, and this is a monkey patch of the offending # code. unless RUBY_VERSION =~ /^2/ require 'fileutils' class FileUtils::Entry_ def copy_metadata(path) st = lstat() if !st.symlink? File.utime st.atime, st.mtime, path end begin if st.symlink? begin File.lchown st.uid, st.gid, path rescue NotImplementedError end else File.chown st.uid, st.gid, path end rescue Errno::EPERM # clear setuid/setgid if st.symlink? begin File.lchmod st.mode & 01777, path rescue NotImplementedError end else File.chmod st.mode & 01777, path end else if st.symlink? begin File.lchmod st.mode, path rescue NotImplementedError end else File.chmod st.mode, path end end end end end chef-11.8.2/lib/chef/monkey_patches/regexp.rb0000644000004100000410000000274012254362222021046 0ustar www-datawww-data# Copyright (c) 2009 Marc-Andre Lafortune # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. class Regexp # Standard in Ruby 1.8.7+. See official documentation[http://www.ruby-doc.org/core-1.8.7/classes/Regexp.html] class << self unless (union(%w(a b)) rescue false) alias :union_without_array_argument :union def union(*arg) return union_without_array_argument(*arg) unless arg.size == 1 union_without_array_argument(*arg.first) end end end end chef-11.8.2/lib/chef/mash.rb0000644000004100000410000001551112254362222015473 0ustar www-datawww-data# Copyright (c) 2009 Dan Kubb # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # --- # --- # Some portions of blank.rb and mash.rb are verbatim copies of software # licensed under the MIT license. That license is included below: # Copyright (c) 2005-2008 David Heinemeier Hansson # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # This class has dubious semantics and we only have it so that people can write # params[:key] instead of params['key']. class Mash < Hash # @param constructor # The default value for the mash. Defaults to an empty hash. # # @details [Alternatives] # If constructor is a Hash, a new mash will be created based on the keys of # the hash and no default value will be set. def initialize(constructor = {}) if constructor.is_a?(Hash) super() update(constructor) else super(constructor) end end # @param orig Mash being copied # # @return [Object] A new copied Mash def initialize_copy(orig) super # Handle nested values each do |k,v| if v.kind_of?(Mash) || v.is_a?(Array) self[k] = v.dup end end self end # @param key The default value for the mash. Defaults to nil. # # @details [Alternatives] # If key is a Symbol and it is a key in the mash, then the default value will # be set to the value matching the key. def default(key = nil) if key.is_a?(Symbol) && include?(key = key.to_s) self[key] else super end end alias_method :regular_writer, :[]= unless method_defined?(:regular_writer) alias_method :regular_update, :update unless method_defined?(:regular_update) # @param key The key to set. # @param value # The value to set the key to. # # @see Mash#convert_key # @see Mash#convert_value def []=(key, value) regular_writer(convert_key(key), convert_value(value)) end # @param other_hash # A hash to update values in the mash with. The keys and the values will be # converted to Mash format. # # @return [Mash] The updated mash. def update(other_hash) other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) } self end alias_method :merge!, :update # @param key The key to check for. This will be run through convert_key. # # @return [Boolean] True if the key exists in the mash. def key?(key) super(convert_key(key)) end # def include? def has_key? def member? alias_method :include?, :key? alias_method :has_key?, :key? alias_method :member?, :key? # @param key The key to fetch. This will be run through convert_key. # @param *extras Default value. # # @return [Object] The value at key or the default value. def fetch(key, *extras) super(convert_key(key), *extras) end # @param *indices # The keys to retrieve values for. These will be run through +convert_key+. # # @return [Array] The values at each of the provided keys def values_at(*indices) indices.collect {|key| self[convert_key(key)]} end # @param hash The hash to merge with the mash. # # @return [Mash] A new mash with the hash values merged in. def merge(hash) self.dup.update(hash) end # @param key # The key to delete from the mash.\ def delete(key) super(convert_key(key)) end # @param *rejected 1, :two => 2, :three => 3 }.except(:one) # #=> { "two" => 2, "three" => 3 } def except(*keys) super(*keys.map {|k| convert_key(k)}) end # Used to provide the same interface as Hash. # # @return [Mash] This mash unchanged. def stringify_keys!; self end # @return [Hash] The mash as a Hash with symbolized keys. def symbolize_keys h = Hash.new(default) each { |key, val| h[key.to_sym] = val } h end # @return [Hash] The mash as a Hash with string keys. def to_hash Hash.new(default).merge(self) end # @return [Mash] Convert a Hash into a Mash # The input Hash's default value is maintained def self.from_hash(hash) mash = Mash.new(hash) mash.default = hash.default mash end protected # @param key The key to convert. # # @param [Object] # The converted key. If the key was a symbol, it will be converted to a # string. # # @api private def convert_key(key) key.kind_of?(Symbol) ? key.to_s : key end # @param value The value to convert. # # @return [Object] # The converted value. A Hash or an Array of hashes, will be converted to # their Mash equivalents. # # @api private def convert_value(value) if value.class == Hash Mash.from_hash(value) elsif value.is_a?(Array) value.collect { |e| convert_value(e) } else value end end end chef-11.8.2/lib/chef/providers.rb0000644000004100000410000001003612254362222016555 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/batch' require 'chef/provider/breakpoint' require 'chef/provider/cookbook_file' require 'chef/provider/cron' require 'chef/provider/cron/solaris' require 'chef/provider/cron/aix' require 'chef/provider/deploy' require 'chef/provider/directory' require 'chef/provider/env' require 'chef/provider/erl_call' require 'chef/provider/execute' require 'chef/provider/file' require 'chef/provider/git' require 'chef/provider/group' require 'chef/provider/http_request' require 'chef/provider/ifconfig' require 'chef/provider/link' require 'chef/provider/log' require 'chef/provider/ohai' require 'chef/provider/mdadm' require 'chef/provider/mount' require 'chef/provider/package' require 'chef/provider/powershell_script' require 'chef/provider/remote_directory' require 'chef/provider/remote_file' require 'chef/provider/route' require 'chef/provider/ruby_block' require 'chef/provider/script' require 'chef/provider/service' require 'chef/provider/subversion' require 'chef/provider/template' require 'chef/provider/user' require 'chef/provider/env/windows' require 'chef/provider/package/apt' require 'chef/provider/package/dpkg' require 'chef/provider/package/easy_install' require 'chef/provider/package/freebsd' require 'chef/provider/package/ips' require 'chef/provider/package/macports' require 'chef/provider/package/pacman' require 'chef/provider/package/portage' require 'chef/provider/package/rpm' require 'chef/provider/package/rubygems' require 'chef/provider/package/yum' require 'chef/provider/package/zypper' require 'chef/provider/package/solaris' require 'chef/provider/package/smartos' require 'chef/provider/package/aix' require 'chef/provider/service/arch' require 'chef/provider/service/debian' require 'chef/provider/service/freebsd' require 'chef/provider/service/gentoo' require 'chef/provider/service/init' require 'chef/provider/service/insserv' require 'chef/provider/service/invokercd' require 'chef/provider/service/redhat' require 'chef/provider/service/simple' require 'chef/provider/service/systemd' require 'chef/provider/service/upstart' require 'chef/provider/service/windows' require 'chef/provider/service/solaris' require 'chef/provider/service/macosx' require 'chef/provider/user/dscl' require 'chef/provider/user/pw' require 'chef/provider/user/useradd' require 'chef/provider/user/windows' require 'chef/provider/user/solaris' require 'chef/provider/group/aix' require 'chef/provider/group/dscl' require 'chef/provider/group/gpasswd' require 'chef/provider/group/groupadd' require 'chef/provider/group/groupmod' require 'chef/provider/group/pw' require 'chef/provider/group/suse' require 'chef/provider/group/usermod' require 'chef/provider/group/windows' require 'chef/provider/mount/mount' require 'chef/provider/mount/aix' require 'chef/provider/mount/windows' require 'chef/provider/deploy/revision' require 'chef/provider/deploy/timestamped' require 'chef/provider/remote_file/ftp' require 'chef/provider/remote_file/http' require 'chef/provider/remote_file/local_file' require 'chef/provider/remote_file/fetcher' require "chef/provider/lwrp_base" require 'chef/provider/registry_key' require 'chef/provider/file/content' require 'chef/provider/remote_file/content' require 'chef/provider/cookbook_file/content' require 'chef/provider/template/content' require 'chef/provider/ifconfig/redhat' require 'chef/provider/ifconfig/debian' require 'chef/provider/ifconfig/aix' chef-11.8.2/lib/chef/role.rb0000644000004100000410000001555112254362222015510 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Nuo Yan () # Author:: Christopher Brown () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/config' require 'chef/mixin/params_validate' require 'chef/mixin/from_file' require 'chef/run_list' require 'chef/mash' require 'chef/json_compat' require 'chef/search/query' class Chef class Role include Chef::Mixin::FromFile include Chef::Mixin::ParamsValidate # Create a new Chef::Role object. def initialize @name = '' @description = '' @default_attributes = Mash.new @override_attributes = Mash.new @env_run_lists = {"_default" => Chef::RunList.new} end def chef_server_rest Chef::REST.new(Chef::Config[:chef_server_url]) end def self.chef_server_rest Chef::REST.new(Chef::Config[:chef_server_url]) end def name(arg=nil) set_or_return( :name, arg, :regex => /^[\-[:alnum:]_]+$/ ) end def description(arg=nil) set_or_return( :description, arg, :kind_of => String ) end def run_list(*args) if (args.length > 0) @env_run_lists["_default"].reset!(args) end @env_run_lists["_default"] end alias_method :recipes, :run_list # For run_list expansion def run_list_for(environment) if env_run_lists[environment].nil? env_run_lists["_default"] else env_run_lists[environment] end end def active_run_list_for(environment) @env_run_lists.has_key?(environment) ? environment : '_default' end # Per environment run lists def env_run_lists(env_run_lists=nil) if (!env_run_lists.nil?) unless env_run_lists.key?("_default") msg = "_default key is required in env_run_lists.\n" msg << "(env_run_lists: #{env_run_lists.inspect})" raise Chef::Exceptions::InvalidEnvironmentRunListSpecification, msg end @env_run_lists.clear env_run_lists.each { |k,v| @env_run_lists[k] = Chef::RunList.new(*Array(v))} end @env_run_lists end alias :env_run_list :env_run_lists def default_attributes(arg=nil) set_or_return( :default_attributes, arg, :kind_of => Hash ) end def override_attributes(arg=nil) set_or_return( :override_attributes, arg, :kind_of => Hash ) end def to_hash env_run_lists_without_default = @env_run_lists.dup env_run_lists_without_default.delete("_default") result = { "name" => @name, "description" => @description, 'json_class' => self.class.name, "default_attributes" => @default_attributes, "override_attributes" => @override_attributes, "chef_type" => "role", #Render to_json correctly for run_list items (both run_list and evn_run_lists) #so malformed json does not result "run_list" => run_list.run_list.map { |item| item.to_s }, "env_run_lists" => env_run_lists_without_default.inject({}) do |accumulator, (k, v)| accumulator[k] = v.map { |x| x.to_s } accumulator end } result end # Serialize this object as a hash def to_json(*a) to_hash.to_json(*a) end def update_from!(o) description(o.description) recipes(o.recipes) if defined?(o.recipes) default_attributes(o.default_attributes) override_attributes(o.override_attributes) env_run_lists(o.env_run_lists) unless o.env_run_lists.nil? self end # Create a Chef::Role from JSON def self.json_create(o) role = new role.name(o["name"]) role.description(o["description"]) role.default_attributes(o["default_attributes"]) role.override_attributes(o["override_attributes"]) # _default run_list is in 'run_list' for newer clients, and # 'recipes' for older clients. env_run_list_hash = {"_default" => (o.has_key?("run_list") ? o["run_list"] : o["recipes"])} # Clients before 0.10 do not include env_run_lists, so only # merge if it's there. if o["env_run_lists"] env_run_list_hash.merge!(o["env_run_lists"]) end role.env_run_lists(env_run_list_hash) role end # Get the list of all roles from the API. def self.list(inflate=false) if inflate response = Hash.new Chef::Search::Query.new.search(:role) do |n| response[n.name] = n unless n.nil? end response else chef_server_rest.get_rest("roles") end end # Load a role by name from the API def self.load(name) chef_server_rest.get_rest("roles/#{name}") end def environment(env_name) chef_server_rest.get_rest("roles/#{@name}/environments/#{env_name}") end def environments chef_server_rest.get_rest("roles/#{@name}/environments") end # Remove this role via the REST API def destroy chef_server_rest.delete_rest("roles/#{@name}") end # Save this role via the REST API def save begin chef_server_rest.put_rest("roles/#{@name}", self) rescue Net::HTTPServerException => e raise e unless e.response.code == "404" chef_server_rest.post_rest("roles", self) end self end # Create the role via the REST API def create chef_server_rest.post_rest("roles", self) self end # As a string def to_s "role[#{@name}]" end # Load a role from disk - prefers to load the JSON, but will happily load # the raw rb files as well. def self.from_disk(name, force=nil) paths = Array(Chef::Config[:role_path]) paths.each do |p| js_file = File.join(p, "#{name}.json") rb_file = File.join(p, "#{name}.rb") if File.exists?(js_file) || force == "json" # from_json returns object.class => json_class in the JSON. return Chef::JSONCompat.from_json(IO.read(js_file)) elsif File.exists?(rb_file) || force == "ruby" role = Chef::Role.new role.name(name) role.from_file(rb_file) return role end end raise Chef::Exceptions::RoleNotFound, "Role '#{name}' could not be loaded from disk" end end end chef-11.8.2/lib/chef/win32/0000755000004100000410000000000012254362222015155 5ustar www-datawww-datachef-11.8.2/lib/chef/win32/file/0000755000004100000410000000000012254362222016074 5ustar www-datawww-datachef-11.8.2/lib/chef/win32/file/info.rb0000644000004100000410000000623212254362222017357 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/file' class Chef module ReservedNames::Win32 class File # Objects of class Chef::ReservedNames::Win32::File::Stat encapsulate common status # information for Chef::ReservedNames::Win32::File objects. The information # is recorded at the moment the Chef::ReservedNames::Win32::File::Stat object is # created; changes made to the file after that point will not be reflected. class Info include Chef::ReservedNames::Win32::API::File include Chef::ReservedNames::Win32::API # http://msdn.microsoft.com/en-us/library/windows/desktop/aa363788(v=vs.85).aspx def initialize(file_name) raise Errno::ENOENT, file_name unless ::File.exist?(file_name) @file_info = retrieve_file_info(file_name) end def volume_serial_number @file_info[:dw_volume_serial_number] end def index make_uint64(@file_info[:n_file_index_low], @file_info[:n_file_index_high]) end def last_access_time parse_time(@file_info[:ft_last_access_time]) end def creation_time parse_time(@file_info[:ft_creation_time]) end def last_write_time parse_time(@file_info[:ft_last_write_time]) end def links @file_info[:n_number_of_links] end def size make_uint64(@file_info[:n_file_size_low], @file_info[:n_file_size_high]) end ############################## # ::File::Stat compat alias :atime :last_access_time alias :mtime :last_write_time alias :ctime :creation_time # we're faking it here, but this is in the spirit of ino in *nix # # from MSDN: # # "The identifier (low and high parts) and the volume serial number # uniquely identify a file on a single computer. To determine whether # two open handles represent the same file, combine the identifier # and the volume serial number for each file and compare them."" # def ino volume_serial_number + index end ############################## # given a +Chef::ReservedNames::Win32::API::File::FILETIME+ structure convert into a # Ruby +Time+ object. # def parse_time(file_time_struct) wtime_to_time(make_uint64(file_time_struct[:dw_low_date_time], file_time_struct[:dw_high_date_time])) end end end end end chef-11.8.2/lib/chef/win32/handle.rb0000644000004100000410000000373612254362222016746 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/api/process' require 'chef/win32/api/psapi' require 'chef/win32/api/system' require 'chef/win32/error' class Chef module ReservedNames::Win32 class Handle extend Chef::ReservedNames::Win32::API::Process # See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683179(v=vs.85).aspx # The handle value returned by the GetCurrentProcess function is the pseudo handle (HANDLE)-1 (which is 0xFFFFFFFF) CURRENT_PROCESS_HANDLE = 4294967295 def initialize(handle) @handle = handle ObjectSpace.define_finalizer(self, Handle.close_handle_finalizer(handle)) end attr_reader :handle def self.close_handle_finalizer(handle) # According to http://msdn.microsoft.com/en-us/library/windows/desktop/ms683179(v=vs.85).aspx, it is not necessary # to close the pseudo handle returned by the GetCurrentProcess function. The docs also say that it doesn't hurt to call # CloseHandle on it. However, doing so from inside of Ruby always seems to produce an invalid handle error. proc { close_handle(handle) unless handle == CURRENT_PROCESS_HANDLE } end def self.close_handle(handle) unless CloseHandle(handle) Chef::ReservedNames::Win32::Error.raise! end end end end end chef-11.8.2/lib/chef/win32/mutex.rb0000644000004100000410000001024212254362222016643 0ustar www-datawww-data# # Author:: Serdar Sutay () # Copyright:: Copyright 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/api/synchronization' class Chef module ReservedNames::Win32 class Mutex include Chef::ReservedNames::Win32::API::Synchronization def initialize(name) @name = name create_system_mutex end attr_reader :handle attr_reader :name ##################################################### # Attempts to grab the mutex. # Returns true if the mutex is grabbed or if it's already # owned; false otherwise. def test WaitForSingleObject(handle, 0) == WAIT_OBJECT_0 end ##################################################### # Attempts to grab the mutex and waits until it is acquired. def wait loop do wait_result = WaitForSingleObject(handle, 1000) case wait_result when WAIT_TIMEOUT # We are periodically waking up in order to give ruby a # chance to process any signal it got while we were # sleeping. This condition shouldn't contain any logic # other than sleeping. sleep 0.1 when WAIT_ABANDONED # Previous owner of the mutex died before it can release the # mutex. Log a warning and continue. Chef::Log.debug "Existing owner of the mutex exited prematurely." break when WAIT_OBJECT_0 # Mutex is successfully acquired. break else Chef::Log.error("Failed to acquire system mutex '#{name}'. Return code: #{wait_result}") Chef::ReservedNames::Win32::Error.raise! end end end ##################################################### # Releaes the mutex def release # http://msdn.microsoft.com/en-us/library/windows/desktop/ms685066(v=vs.85).aspx # Note that release method needs to be called more than once # if mutex is acquired more than once. unless ReleaseMutex(handle) # Don't fail things in here if we can't release the mutex. # Because it will be automatically released when the owner # of the process goes away and this class is only being used # to synchronize chef-clients runs on a node. Chef::Log.error("Can not release mutex '#{name}'. This might cause issues \ if the mutex is attempted to be acquired by other threads.") Chef::ReservedNames::Win32::Error.raise! end end private def create_system_mutex # First check if there exists a mutex in the system with the # given name. We need only synchronize rights if a mutex is # already created. # InheritHandle is set to true so that subprocesses can # inherit the ownership of the mutex. @handle = OpenMutexW(SYNCHRONIZE, true, name.to_wstring) if @handle == 0 # Mutext doesn't exist so create one. # In the initial creation of the mutex initial_owner is set to # false so that mutex will not be acquired until someone calls # acquire. # In order to call "*W" windows apis, strings needs to be # encoded as wide strings. @handle = CreateMutexW(nil, false, name.to_wstring) # Looks like we can't create the mutex for some reason. # Fail early. if @handle == 0 Chef::Log.error("Failed to create system mutex with name'#{name}'") Chef::ReservedNames::Win32::Error.raise! end end end end end end chef-11.8.2/lib/chef/win32/security/0000755000004100000410000000000012254362222017024 5ustar www-datawww-datachef-11.8.2/lib/chef/win32/security/ace.rb0000644000004100000410000000734112254362222020106 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/security' require 'chef/win32/security/sid' require 'chef/win32/memory' require 'ffi' class Chef module ReservedNames::Win32 class Security class ACE def initialize(pointer, owner = nil) if Chef::ReservedNames::Win32::API::Security::ACE_WITH_MASK_AND_SID.supports?(pointer.read_uchar) @struct = Chef::ReservedNames::Win32::API::Security::ACE_WITH_MASK_AND_SID.new pointer else # TODO Support ALL the things @struct = Chef::ReservedNames::Win32::API::Security::ACE_HEADER.new pointer end # Keep a reference to the actual owner of this memory so we don't get freed @owner = owner end def self.size_with_sid(sid) Chef::ReservedNames::Win32::API::Security::ACE_WITH_MASK_AND_SID.offset_of(:SidStart) + sid.size end def self.access_allowed(sid, mask, flags = 0) create_ace_with_mask_and_sid(Chef::ReservedNames::Win32::API::Security::ACCESS_ALLOWED_ACE_TYPE, flags, mask, sid) end def self.access_denied(sid, mask, flags = 0) create_ace_with_mask_and_sid(Chef::ReservedNames::Win32::API::Security::ACCESS_DENIED_ACE_TYPE, flags, mask, sid) end attr_reader :struct def ==(other) type == other.type && flags == other.flags && mask == other.mask && sid == other.sid end def dup ACE.create_ace_with_mask_and_sid(type, flags, mask, sid) end def flags struct[:AceFlags] end def flags=(val) struct[:AceFlags] = val end def explicit? ! inherited? end def inherited? (struct[:AceFlags] & Chef::ReservedNames::Win32::API::Security::INHERITED_ACE) != 0 end def mask struct[:Mask] end def mask=(val) struct[:Mask] = val end def pointer struct.pointer end def size struct[:AceSize] end def sid # The SID runs off the end of the structure, starting at :SidStart. # Use pointer arithmetic to get a pointer to that location. Chef::ReservedNames::Win32::Security::SID.new(struct.pointer + struct.offset_of(:SidStart)) end def to_s "#{sid.account_name}/flags:#{flags.to_s(16)}/mask:#{mask.to_s(16)}" end def type struct[:AceType] end private def self.create_ace_with_mask_and_sid(type, flags, mask, sid) size_needed = size_with_sid(sid) pointer = FFI::MemoryPointer.new size_needed struct = Chef::ReservedNames::Win32::API::Security::ACE_WITH_MASK_AND_SID.new pointer struct[:AceType] = type struct[:AceFlags] = flags struct[:AceSize] = size_needed struct[:Mask] = mask Chef::ReservedNames::Win32::Memory.memcpy(struct.pointer + struct.offset_of(:SidStart), sid.pointer, sid.size) ACE.new(struct.pointer) end end end end end chef-11.8.2/lib/chef/win32/security/sid.rb0000644000004100000410000001301312254362222020126 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/security' class Chef module ReservedNames::Win32 class Security class SID def initialize(pointer, owner = nil) @pointer = pointer # Keep a reference to the actual owner of this memory so we don't get freed @owner = owner end def self.from_account(name) domain, sid, use = Chef::ReservedNames::Win32::Security.lookup_account_name(name) sid end def self.from_string_sid(string_sid) Chef::ReservedNames::Win32::Security::convert_string_sid_to_sid(string_sid) end def ==(other) other != nil && Chef::ReservedNames::Win32::Security.equal_sid(self, other) end attr_reader :pointer def account Chef::ReservedNames::Win32::Security.lookup_account_sid(self) end def account_name domain, name, use = account (domain != nil && domain.length > 0) ? "#{domain}\\#{name}" : name end def size Chef::ReservedNames::Win32::Security.get_length_sid(self) end def to_s Chef::ReservedNames::Win32::Security.convert_sid_to_string_sid(self) end def valid? Chef::ReservedNames::Win32::Security.is_valid_sid(self) end # Well-known SIDs def self.Null SID.from_string_sid('S-1-0') end def self.Nobody SID.from_string_sid('S-1-0-0') end def self.World SID.from_string_sid('S-1-1') end def self.Everyone SID.from_string_sid('S-1-1-0') end def self.Local SID.from_string_sid('S-1-2') end def self.Creator SID.from_string_sid('S-1-3') end def self.CreatorOwner SID.from_string_sid('S-1-3-0') end def self.CreatorGroup SID.from_string_sid('S-1-3-1') end def self.CreatorOwnerServer SID.from_string_sid('S-1-3-2') end def self.CreatorGroupServer SID.from_string_sid('S-1-3-3') end def self.NonUnique SID.from_string_sid('S-1-4') end def self.Nt SID.from_string_sid('S-1-5') end def self.Dialup SID.from_string_sid('S-1-5-1') end def self.Network SID.from_string_sid('S-1-5-2') end def self.Batch SID.from_string_sid('S-1-5-3') end def self.Interactive SID.from_string_sid('S-1-5-4') end def self.Service SID.from_string_sid('S-1-5-6') end def self.Anonymous SID.from_string_sid('S-1-5-7') end def self.Proxy SID.from_string_sid('S-1-5-8') end def self.EnterpriseDomainControllers SID.from_string_sid('S-1-5-9') end def self.PrincipalSelf SID.from_string_sid('S-1-5-10') end def self.AuthenticatedUsers SID.from_string_sid('S-1-5-11') end def self.RestrictedCode SID.from_string_sid('S-1-5-12') end def self.TerminalServerUsers SID.from_string_sid('S-1-5-13') end def self.LocalSystem SID.from_string_sid('S-1-5-18') end def self.NtLocal SID.from_string_sid('S-1-5-19') end def self.NtNetwork SID.from_string_sid('S-1-5-20') end def self.BuiltinAdministrators SID.from_string_sid('S-1-5-32-544') end def self.BuiltinUsers SID.from_string_sid('S-1-5-32-545') end def self.Guests SID.from_string_sid('S-1-5-32-546') end def self.PowerUsers SID.from_string_sid('S-1-5-32-547') end def self.AccountOperators SID.from_string_sid('S-1-5-32-548') end def self.ServerOperators SID.from_string_sid('S-1-5-32-549') end def self.PrintOperators SID.from_string_sid('S-1-5-32-550') end def self.BackupOperators SID.from_string_sid('S-1-5-32-551') end def self.Replicators SID.from_string_sid('S-1-5-32-552') end def self.Administrators SID.from_string_sid('S-1-5-32-544') end # Machine-specific, well-known SIDs # TODO: don't use strings, dummy def self.None SID.from_account("#{::ENV['COMPUTERNAME']}\\None") end def self.Administrator SID.from_account("#{::ENV['COMPUTERNAME']}\\Administrator") end def self.Guest SID.from_account("#{::ENV['COMPUTERNAME']}\\Guest") end def self.current_user SID.from_account("#{::ENV['USERDOMAIN']}\\#{::ENV['USERNAME']}") end end end end end chef-11.8.2/lib/chef/win32/security/acl.rb0000644000004100000410000000561712254362222020121 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/security' require 'chef/win32/security/ace' require 'ffi' class Chef module ReservedNames::Win32 class Security class ACL include Enumerable def initialize(pointer, owner = nil) @struct = Chef::ReservedNames::Win32::API::Security::ACLStruct.new pointer # Keep a reference to the actual owner of this memory so that it isn't freed out from under us # TODO this could be avoided if we could mark a pointer's parent manually @owner = owner end def self.create(aces) aces_size = aces.inject(0) { |sum,ace| sum + ace.size } acl_size = align_dword(Chef::ReservedNames::Win32::API::Security::ACLStruct.size + aces_size) # What the heck is 94??? acl = Chef::ReservedNames::Win32::Security.initialize_acl(acl_size) aces.each { |ace| Chef::ReservedNames::Win32::Security.add_ace(acl, ace) } acl end attr_reader :struct def ==(other) return false if length != other.length 0.upto(length-1) do |i| return false if self[i] != other[i] end return true end def pointer struct.pointer end def [](index) Chef::ReservedNames::Win32::Security.get_ace(self, index) end def delete_at(index) Chef::ReservedNames::Win32::Security.delete_ace(self, index) end def each 0.upto(length-1) { |i| yield self[i] } end def insert(index, *aces) aces.reverse_each { |ace| add_ace(self, ace, index) } end def length struct[:AceCount] end def push(*aces) aces.each { |ace| Chef::ReservedNames::Win32::Security.add_ace(self, ace) } end def unshift(*aces) aces.each { |ace| Chef::ReservedNames::Win32::Security.add_ace(self, ace, 0) } end def valid? Chef::ReservedNames::Win32::Security.is_valid_acl(self) end def to_s "[#{self.collect { |ace| ace.to_s }.join(", ")}]" end private def self.align_dword(size) (size + 4 - 1) & 0xfffffffc end end end end end chef-11.8.2/lib/chef/win32/security/securable_object.rb0000644000004100000410000001227512254362222022653 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/security' require 'chef/win32/security/acl' require 'chef/win32/security/sid' class Chef module ReservedNames::Win32 class Security class SecurableObject def initialize(path, type = :SE_FILE_OBJECT) @path = path @type = type end attr_reader :path attr_reader :type SecurityConst = Chef::ReservedNames::Win32::API::Security # This method predicts what the rights mask would be on an object # if you created an ACE with the given mask. Specifically, it looks for # generic attributes like GENERIC_READ, and figures out what specific # attributes will be set. This is important if you want to try to # compare an existing ACE with one you want to create. def predict_rights_mask(generic_mask) mask = generic_mask #mask |= Chef::ReservedNames::Win32::API::Security::STANDARD_RIGHTS_READ if (mask | Chef::ReservedNames::Win32::API::Security::GENERIC_READ) != 0 #mask |= Chef::ReservedNames::Win32::API::Security::STANDARD_RIGHTS_WRITE if (mask | Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE) != 0 #mask |= Chef::ReservedNames::Win32::API::Security::STANDARD_RIGHTS_EXECUTE if (mask | Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE) != 0 #mask |= Chef::ReservedNames::Win32::API::Security::STANDARD_RIGHTS_ALL if (mask | Chef::ReservedNames::Win32::API::Security::GENERIC_ALL) != 0 if type == :SE_FILE_OBJECT mask |= Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_READ if (mask & Chef::ReservedNames::Win32::API::Security::GENERIC_READ) != 0 mask |= Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE if (mask & Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE) != 0 mask |= Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_EXECUTE if (mask & Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE) != 0 mask |= Chef::ReservedNames::Win32::API::Security::FILE_ALL_ACCESS if (mask & Chef::ReservedNames::Win32::API::Security::GENERIC_ALL) != 0 else raise "Unimplemented object type for predict_security_mask: #{type}" end mask &= ~(Chef::ReservedNames::Win32::API::Security::GENERIC_READ | Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE | Chef::ReservedNames::Win32::API::Security::GENERIC_EXECUTE | Chef::ReservedNames::Win32::API::Security::GENERIC_ALL) mask end def security_descriptor(include_sacl = false) security_information = Chef::ReservedNames::Win32::API::Security::OWNER_SECURITY_INFORMATION | Chef::ReservedNames::Win32::API::Security::GROUP_SECURITY_INFORMATION | Chef::ReservedNames::Win32::API::Security::DACL_SECURITY_INFORMATION if include_sacl security_information |= Chef::ReservedNames::Win32::API::Security::SACL_SECURITY_INFORMATION Security.with_privileges("SeSecurityPrivilege") do Security.get_named_security_info(path, type, security_information) end else Security.get_named_security_info(path, type, security_information) end end def dacl=(val) Security.set_named_security_info(path, type, :dacl => val) end # You don't set dacl_inherits without also setting dacl, # because Windows gets angry and denies you access. So # if you want to do that, you may as well do both at once. def set_dacl(dacl, dacl_inherits) Security.set_named_security_info(path, type, :dacl => dacl, :dacl_inherits => dacl_inherits) end def group=(val) Security.set_named_security_info(path, type, :group => val) end def owner=(val) # TODO to fix serious permissions problems, we may need to enable SeBackupPrivilege. But we might need it (almost) everywhere else, too. Security.with_privileges("SeTakeOwnershipPrivilege", "SeRestorePrivilege") do Security.set_named_security_info(path, type, :owner => val) end end def sacl=(val) Security.with_privileges("SeSecurityPrivilege") do Security.set_named_security_info(path, type, :sacl => val) end end def set_sacl(sacl, sacl_inherits) Security.with_privileges("SeSecurityPrivilege") do Security.set_named_security_info(path, type, :sacl => sacl, :sacl_inherits => sacl_inherits) end end end end end end chef-11.8.2/lib/chef/win32/security/security_descriptor.rb0000644000004100000410000000530512254362222023461 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/security' require 'chef/win32/security/acl' require 'chef/win32/security/sid' class Chef module ReservedNames::Win32 class Security class SecurityDescriptor def initialize(pointer) @pointer = pointer end attr_reader :pointer def absolute? !self_relative? end def control control, version = Chef::ReservedNames::Win32::Security.get_security_descriptor_control(self) control end def dacl raise "DACL not present" if !dacl_present? present, acl, defaulted = Chef::ReservedNames::Win32::Security.get_security_descriptor_dacl(self) acl end def dacl_inherits? (control & Chef::ReservedNames::Win32::API::Security::SE_DACL_PROTECTED) == 0 end def dacl_present? (control & Chef::ReservedNames::Win32::API::Security::SE_DACL_PRESENT) != 0 end def group result, defaulted = Chef::ReservedNames::Win32::Security.get_security_descriptor_group(self) result end def owner result, defaulted = Chef::ReservedNames::Win32::Security.get_security_descriptor_owner(self) result end def sacl raise "SACL not present" if !sacl_present? Security.with_privileges("SeSecurityPrivilege") do present, acl, defaulted = Chef::ReservedNames::Win32::Security.get_security_descriptor_sacl(self) acl end end def sacl_inherits? (control & Chef::ReservedNames::Win32::API::Security::SE_SACL_PROTECTED) == 0 end def sacl_present? (control & Chef::ReservedNames::Win32::API::Security::SE_SACL_PRESENT) != 0 end def self_relative? (control & Chef::ReservedNames::Win32::API::Security::SE_SELF_RELATIVE) != 0 end def valid? Chef::ReservedNames::Win32::Security.is_valid_security_descriptor(self) end end end end end chef-11.8.2/lib/chef/win32/security/token.rb0000644000004100000410000000474712254362222020505 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/security' require 'chef/win32/api/security' require 'ffi' class Chef module ReservedNames::Win32 class Security class Token def initialize(handle) @handle = handle end attr_reader :handle def enable_privileges(*privilege_names) # Build the list of privileges we want to set new_privileges = Chef::ReservedNames::Win32::API::Security::TOKEN_PRIVILEGES.new( FFI::MemoryPointer.new(Chef::ReservedNames::Win32::API::Security::TOKEN_PRIVILEGES.size_with_privileges(privilege_names.length))) new_privileges[:PrivilegeCount] = 0 privilege_names.each do |privilege_name| luid = Chef::ReservedNames::Win32::API::Security::LUID.new # Ignore failure (with_privileges TRIES but does not guarantee success-- # APIs down the line will fail if privilege escalation fails) if Chef::ReservedNames::Win32::API::Security.LookupPrivilegeValueW(nil, privilege_name.to_wstring, luid) new_privilege = new_privileges.privilege(new_privileges[:PrivilegeCount]) new_privilege[:Luid][:LowPart] = luid[:LowPart] new_privilege[:Luid][:HighPart] = luid[:HighPart] new_privilege[:Attributes] = Chef::ReservedNames::Win32::API::Security::SE_PRIVILEGE_ENABLED new_privileges[:PrivilegeCount] = new_privileges[:PrivilegeCount] + 1 end end old_privileges = Chef::ReservedNames::Win32::Security.adjust_token_privileges(self, new_privileges) end def adjust_privileges(privileges_struct) if privileges_struct[:PrivilegeCount] > 0 Chef::ReservedNames::Win32::Security::adjust_token_privileges(self, privileges_struct) end end end end end end chef-11.8.2/lib/chef/win32/process.rb0000644000004100000410000000467112254362222017170 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/api/process' require 'chef/win32/api/psapi' require 'chef/win32/error' require 'chef/win32/handle' require 'ffi' class Chef module ReservedNames::Win32 class Process include Chef::ReservedNames::Win32::API::Process extend Chef::ReservedNames::Win32::API::Process include Chef::ReservedNames::Win32::API::PSAPI extend Chef::ReservedNames::Win32::API::PSAPI def initialize(handle) @handle = handle end attr_reader :handle def id Process.get_process_id(handle) end def handle_count Process.get_process_handle_count(handle) end def memory_info Process.get_process_memory_info(handle) end def self.get_current_process Process.new(Handle.new(GetCurrentProcess())) end def self.get_process_handle_count(handle) handle_count = FFI::MemoryPointer.new :uint32 unless GetProcessHandleCount(handle.handle, handle_count) Chef::ReservedNames::Win32::Error.raise! end handle_count.read_uint32 end def self.get_process_id(handle) # Must have PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION rights result = GetProcessId(handle.handle) if result == 0 Chef::ReservedNames::Win32::Error.raise! end result end # Must have PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION rights, # AND the PROCESS_VM_READ right def self.get_process_memory_info(handle) memory_info = PROCESS_MEMORY_COUNTERS.new unless GetProcessMemoryInfo(handle.handle, memory_info, memory_info.size) Chef::ReservedNames::Win32::Error.raise! end memory_info end end end end chef-11.8.2/lib/chef/win32/memory.rb0000644000004100000410000000604112254362222017013 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/error' require 'chef/win32/api/memory' class Chef module ReservedNames::Win32 class Memory include Chef::ReservedNames::Win32::API::Memory extend Chef::ReservedNames::Win32::API::Memory # local_alloc(length[, flags]) [BLOCK] # Allocates memory using LocalAlloc # If BLOCK is specified, the memory will be passed # to the block and freed afterwards. def self.local_alloc(length, flags = LPTR, &block) result = LocalAlloc(flags, length) if result.null? Chef::ReservedNames::Win32::Error.raise! end # If a block is passed, handle freeing the memory at the end if block != nil begin yield result ensure local_free(result) end else result end end # local_discard(pointer) # Discard memory. Equivalent to local_realloc(pointer, 0) def self.local_discard(pointer) local_realloc(pointer, 0, LMEM_MOVEABLE) end # local_flags(pointer) # Get lock count and Windows flags for local_alloc allocated memory. # Use: flags, lock_count = local_flags(pointer) def self.local_flags(pointer) result = LocalFlags(pointer) if result == LMEM_INVALID_HANDLE Chef::ReservedNames::Win32::Error.raise! end [ result & ~LMEM_LOCKCOUNT, result & LMEM_LOCKCOUNT ] end # local_free(pointer) # Free memory allocated using local_alloc def self.local_free(pointer) result = LocalFree(pointer) if !result.null? Chef::ReservedNames::Win32::Error.raise! end end # local_realloc(pointer, size[, flags]) # Resizes memory allocated using LocalAlloc. def self.local_realloc(pointer, size, flags = LMEM_MOVEABLE | LMEM_ZEROINIT) result = LocalReAlloc(pointer, size, flags) if result.null? Chef::ReservedNames::Win32::Error.raise! end result end # local_size(pointer) # Gets the size of memory allocated using LocalAlloc. def self.local_size(pointer) result = LocalSize(pointer) if result == 0 Chef::ReservedNames::Win32::Error.raise! end result end def self.local_free_finalizer(pointer) proc { local_free(pointer) } end end end end chef-11.8.2/lib/chef/win32/security.rb0000644000004100000410000005310112254362222017351 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/api/security' require 'chef/win32/error' require 'chef/win32/memory' require 'chef/win32/process' require 'chef/win32/unicode' require 'chef/win32/security/token' class Chef module ReservedNames::Win32 class Security include Chef::ReservedNames::Win32::API::Error extend Chef::ReservedNames::Win32::API::Error include Chef::ReservedNames::Win32::API::Security extend Chef::ReservedNames::Win32::API::Security extend Chef::ReservedNames::Win32::API::Macros def self.add_ace(acl, ace, insert_position = MAXDWORD, revision = ACL_REVISION) acl = acl.pointer if acl.respond_to?(:pointer) ace = ace.pointer if ace.respond_to?(:pointer) ace_size = ACE_HEADER.new(ace)[:AceSize] unless AddAce(acl, revision, insert_position, ace, ace_size) Chef::ReservedNames::Win32::Error.raise! end end def self.add_access_allowed_ace(acl, sid, access_mask, revision = ACL_REVISION) acl = acl.pointer if acl.respond_to?(:pointer) sid = sid.pointer if sid.respond_to?(:pointer) unless AddAccessAllowedAce(acl, revision, access_mask, sid) Chef::ReservedNames::Win32::Error.raise! end end def self.add_access_allowed_ace_ex(acl, sid, access_mask, flags = 0, revision = ACL_REVISION) acl = acl.pointer if acl.respond_to?(:pointer) sid = sid.pointer if sid.respond_to?(:pointer) unless AddAccessAllowedAceEx(acl, revision, flags, access_mask, sid) Chef::ReservedNames::Win32::Error.raise! end end def self.add_access_denied_ace(acl, sid, access_mask, revision = ACL_REVISION) acl = acl.pointer if acl.respond_to?(:pointer) sid = sid.pointer if sid.respond_to?(:pointer) unless AddAccessDeniedAce(acl, revision, access_mask, sid) Chef::ReservedNames::Win32::Error.raise! end end def self.add_access_denied_ace_ex(acl, sid, access_mask, flags = 0, revision = ACL_REVISION) acl = acl.pointer if acl.respond_to?(:pointer) sid = sid.pointer if sid.respond_to?(:pointer) unless AddAccessDeniedAceEx(acl, revision, flags, access_mask, sid) Chef::ReservedNames::Win32::Error.raise! end end def self.adjust_token_privileges(token, privileges) token = token.handle if token.respond_to?(:handle) old_privileges_size = FFI::Buffer.new(:long).write_long(privileges.size_with_privileges) old_privileges = TOKEN_PRIVILEGES.new(FFI::Buffer.new(old_privileges_size.read_long)) unless AdjustTokenPrivileges(token.handle, false, privileges, privileges.size_with_privileges, old_privileges, old_privileges_size) Chef::ReservedNames::Win32::Error.raise! end old_privileges end def self.convert_sid_to_string_sid(sid) sid = sid.pointer if sid.respond_to?(:pointer) result = FFI::MemoryPointer.new :pointer # TODO: use the W version unless ConvertSidToStringSidA(sid, result) Chef::ReservedNames::Win32::Error.raise! end result_string = result.read_pointer.read_string Chef::ReservedNames::Win32::Memory.local_free(result.read_pointer) result_string end def self.convert_string_sid_to_sid(string_sid) result = FFI::MemoryPointer.new :pointer unless ConvertStringSidToSidW(string_sid.to_wstring, result) Chef::ReservedNames::Win32::Error.raise! end result_pointer = result.read_pointer sid = SID.new(result_pointer) # The result pointer must be freed with local_free ObjectSpace.define_finalizer(sid, Memory.local_free_finalizer(result_pointer)) sid end def self.delete_ace(acl, index) acl = acl.pointer if acl.respond_to?(:pointer) unless DeleteAce(acl, index) Chef::ReservedNames::Win32::Error.raise! end end def self.equal_sid(sid1, sid2) sid1 = sid1.pointer if sid1.respond_to?(:pointer) sid2 = sid2.pointer if sid2.respond_to?(:pointer) EqualSid(sid1, sid2) end def self.free_sid(sid) sid = sid.pointer if sid.respond_to?(:pointer) unless FreeSid(sid).null? Chef::ReservedNames::Win32::Error.raise! end end def self.get_ace(acl, index) acl = acl.pointer if acl.respond_to?(:pointer) ace = FFI::Buffer.new :pointer unless GetAce(acl, index, ace) Chef::ReservedNames::Win32::Error.raise! end ACE.new(ace.read_pointer, acl) end def self.get_length_sid(sid) sid = sid.pointer if sid.respond_to?(:pointer) GetLengthSid(sid) end def self.get_named_security_info(path, type = :SE_FILE_OBJECT, info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION) security_descriptor = FFI::MemoryPointer.new :pointer hr = GetNamedSecurityInfoW(path.to_wstring, type, info, nil, nil, nil, nil, security_descriptor) if hr != ERROR_SUCCESS Chef::ReservedNames::Win32::Error.raise!("get_named_security_info(#{path}, #{type}, #{info})") end result_pointer = security_descriptor.read_pointer result = SecurityDescriptor.new(result_pointer) # This memory has to be freed with LocalFree. ObjectSpace.define_finalizer(result, Memory.local_free_finalizer(result_pointer)) result end def self.get_security_descriptor_control(security_descriptor) security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) result = FFI::Buffer.new :ushort version = FFI::Buffer.new :uint32 unless GetSecurityDescriptorControl(security_descriptor, result, version) Chef::ReservedNames::Win32::Error.raise! end [ result.read_ushort, version.read_uint32 ] end def self.get_security_descriptor_dacl(security_descriptor) security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) present = FFI::Buffer.new :bool defaulted = FFI::Buffer.new :bool acl = FFI::Buffer.new :pointer unless GetSecurityDescriptorDacl(security_descriptor, present, acl, defaulted) Chef::ReservedNames::Win32::Error.raise! end acl = acl.read_pointer [ present.read_char != 0, acl.null? ? nil : ACL.new(acl, security_descriptor), defaulted.read_char != 0 ] end def self.get_security_descriptor_group(security_descriptor) security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) result = FFI::Buffer.new :pointer defaulted = FFI::Buffer.new :long unless GetSecurityDescriptorGroup(security_descriptor, result, defaulted) Chef::ReservedNames::Win32::Error.raise! end sid = SID.new(result.read_pointer, security_descriptor) defaulted = defaulted.read_char != 0 [ sid, defaulted ] end def self.get_security_descriptor_owner(security_descriptor) security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) result = FFI::Buffer.new :pointer defaulted = FFI::Buffer.new :long unless GetSecurityDescriptorOwner(security_descriptor, result, defaulted) Chef::ReservedNames::Win32::Error.raise! end sid = SID.new(result.read_pointer, security_descriptor) defaulted = defaulted.read_char != 0 [ sid, defaulted ] end def self.get_security_descriptor_sacl(security_descriptor) security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) present = FFI::Buffer.new :bool defaulted = FFI::Buffer.new :bool acl = FFI::Buffer.new :pointer unless GetSecurityDescriptorSacl(security_descriptor, present, acl, defaulted) Chef::ReservedNames::Win32::Error.raise! end acl = acl.read_pointer [ present.read_char != 0, acl.null? ? nil : ACL.new(acl, security_descriptor), defaulted.read_char != 0 ] end def self.initialize_acl(acl_size) acl = FFI::MemoryPointer.new acl_size unless InitializeAcl(acl, acl_size, ACL_REVISION) Chef::ReservedNames::Win32::Error.raise! end ACL.new(acl) end def self.initialize_security_descriptor(revision = SECURITY_DESCRIPTOR_REVISION) security_descriptor = FFI::MemoryPointer.new SECURITY_DESCRIPTOR_MIN_LENGTH unless InitializeSecurityDescriptor(security_descriptor, revision) Chef::ReservedNames::Win32::Error.raise! end SecurityDescriptor.new(security_descriptor) end def self.is_valid_acl(acl) acl = acl.pointer if acl.respond_to?(:pointer) IsValidAcl(acl) != 0 end def self.is_valid_security_descriptor(security_descriptor) security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) IsValidSecurityDescriptor(security_descriptor) != 0 end def self.is_valid_sid(sid) sid = sid.pointer if sid.respond_to?(:pointer) IsValidSid(sid) != 0 end def self.lookup_account_name(name, system_name = nil) # Figure out how big the buffers need to be sid_size = FFI::Buffer.new(:long).write_long(0) referenced_domain_name_size = FFI::Buffer.new(:long).write_long(0) system_name = system_name.to_wstring if system_name if LookupAccountNameW(system_name, name.to_wstring, nil, sid_size, nil, referenced_domain_name_size, nil) raise "Expected ERROR_INSUFFICIENT_BUFFER from LookupAccountName, and got no error!" elsif Chef::ReservedNames::Win32::Error.get_last_error != ERROR_INSUFFICIENT_BUFFER Chef::ReservedNames::Win32::Error.raise! end sid = FFI::MemoryPointer.new :char, sid_size.read_long referenced_domain_name = FFI::MemoryPointer.new :char, (referenced_domain_name_size.read_long*2) use = FFI::Buffer.new(:long).write_long(0) unless LookupAccountNameW(system_name, name.to_wstring, sid, sid_size, referenced_domain_name, referenced_domain_name_size, use) Chef::ReservedNames::Win32::Error.raise! end [ referenced_domain_name.read_wstring(referenced_domain_name_size.read_long), SID.new(sid), use.read_long ] end def self.lookup_account_sid(sid, system_name = nil) sid = sid.pointer if sid.respond_to?(:pointer) # Figure out how big the buffer needs to be name_size = FFI::Buffer.new(:long).write_long(0) referenced_domain_name_size = FFI::Buffer.new(:long).write_long(0) system_name = system_name.to_wstring if system_name if LookupAccountSidW(system_name, sid, nil, name_size, nil, referenced_domain_name_size, nil) raise "Expected ERROR_INSUFFICIENT_BUFFER from LookupAccountSid, and got no error!" elsif Chef::ReservedNames::Win32::Error::get_last_error != ERROR_INSUFFICIENT_BUFFER Chef::ReservedNames::Win32::Error.raise! end name = FFI::MemoryPointer.new :char, (name_size.read_long*2) referenced_domain_name = FFI::MemoryPointer.new :char, (referenced_domain_name_size.read_long*2) use = FFI::Buffer.new(:long).write_long(0) unless LookupAccountSidW(system_name, sid, name, name_size, referenced_domain_name, referenced_domain_name_size, use) Chef::ReservedNames::Win32::Error.raise! end [ referenced_domain_name.read_wstring(referenced_domain_name_size.read_long), name.read_wstring(name_size.read_long), use.read_long ] end def self.lookup_privilege_name(system_name, luid) system_name = system_name.to_wstring if system_name name_size = FFI::Buffer.new(:long).write_long(0) if LookupPrivilegeNameW(system_name, luid, nil, name_size) raise "Expected ERROR_INSUFFICIENT_BUFFER from LookupPrivilegeName, and got no error!" elsif Chef::ReservedNames::Win32::Error.get_last_error != ERROR_INSUFFICIENT_BUFFER Chef::ReservedNames::Win32::Error.raise! end name = FFI::MemoryPointer.new :char, (name_size.read_long*2) unless LookupPrivilegeNameW(system_name, luid, name, name_size) Chef::ReservedNames::Win32::Error.raise! end name.read_wstring(name_size.read_long) end def self.lookup_privilege_display_name(system_name, name) system_name = system_name.to_wstring if system_name display_name_size = FFI::Buffer.new(:long).write_long(0) language_id = FFI::Buffer.new(:long) if LookupPrivilegeDisplayNameW(system_name, name.to_wstring, nil, display_name_size, language_id) raise "Expected ERROR_INSUFFICIENT_BUFFER from LookupPrivilegeDisplayName, and got no error!" elsif Chef::ReservedNames::Win32::Error.get_last_error != ERROR_INSUFFICIENT_BUFFER Chef::ReservedNames::Win32::Error.raise! end display_name = FFI::MemoryPointer.new :char, (display_name_size.read_long*2) unless LookupPrivilegeDisplayNameW(system_name, name.to_wstring, display_name, display_name_size, language_id) Chef::ReservedNames::Win32::Error.raise! end [ display_name.read_wstring(display_name_size.read_long), language_id.read_long ] end def self.lookup_privilege_value(system_name, name) luid = FFI::Buffer.new(:uint64).write_uint64(0) system_name = system_name.to_wstring if system_name unless LookupPrivilegeValueW(system_name, name.to_wstring, luid) Win32::Error.raise! end luid.read_uint64 end def self.make_absolute_sd(security_descriptor) security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) # Figure out buffer sizes absolute_sd_size = FFI::Buffer.new(:long).write_long(0) dacl_size = FFI::Buffer.new(:long).write_long(0) sacl_size = FFI::Buffer.new(:long).write_long(0) owner_size = FFI::Buffer.new(:long).write_long(0) group_size = FFI::Buffer.new(:long).write_long(0) if MakeAbsoluteSD(security_descriptor, nil, absolute_sd_size, nil, dacl_size, nil, sacl_size, nil, owner_size, nil, group_size) raise "Expected ERROR_INSUFFICIENT_BUFFER from MakeAbsoluteSD, and got no error!" elsif Chef::ReservedNames::Win32::Error.get_last_error != ERROR_INSUFFICIENT_BUFFER Chef::ReservedNames::Win32::Error.raise! end absolute_sd = FFI::MemoryPointer.new absolute_sd_size.read_long owner = FFI::MemoryPointer.new owner_size.read_long group = FFI::MemoryPointer.new group_size.read_long dacl = FFI::MemoryPointer.new dacl_size.read_long sacl = FFI::MemoryPointer.new sacl_size.read_long unless MakeAbsoluteSD(security_descriptor, absolute_sd, absolute_sd_size, dacl, dacl_size, sacl, sacl_size, owner, owner_size, group, group_size) Chef::ReservedNames::Win32::Error.raise! end [ SecurityDescriptor.new(absolute_sd), SID.new(owner), SID.new(group), ACL.new(dacl), ACL.new(sacl) ] end def self.open_process_token(process, desired_access) process = process.handle if process.respond_to?(:handle) process = process.handle if process.respond_to?(:handle) token = FFI::Buffer.new(:ulong) unless OpenProcessToken(process, desired_access, token) Chef::ReservedNames::Win32::Error.raise! end Token.new(Handle.new(token.read_ulong)) end def self.query_security_access_mask(security_information) result = FFI::Buffer.new(:long) QuerySecurityAccessMask(security_information, result) result.read_long end def self.set_file_security(path, security_information, security_descriptor) security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) unless SetFileSecurityW(path.to_wstring, security_information, security_descriptor) Chef::ReservedNames::Win32::Error.raise! end end def self.set_named_security_info(path, type, args) owner = args[:owner] group = args[:group] dacl = args[:dacl] sacl = args[:sacl] owner = owner.pointer if owner && owner.respond_to?(:pointer) group = group.pointer if group && group.respond_to?(:pointer) dacl = dacl.pointer if dacl && dacl.respond_to?(:pointer) sacl = sacl.pointer if sacl && sacl.respond_to?(:pointer) # Determine the security_information flags security_information = 0 security_information |= OWNER_SECURITY_INFORMATION if args.has_key?(:owner) security_information |= GROUP_SECURITY_INFORMATION if args.has_key?(:group) security_information |= DACL_SECURITY_INFORMATION if args.has_key?(:dacl) security_information |= SACL_SECURITY_INFORMATION if args.has_key?(:sacl) if args.has_key?(:dacl_inherits) security_information |= (args[:dacl_inherits] ? UNPROTECTED_DACL_SECURITY_INFORMATION : PROTECTED_DACL_SECURITY_INFORMATION) end if args.has_key?(:sacl_inherits) security_information |= (args[:sacl_inherits] ? UNPROTECTED_SACL_SECURITY_INFORMATION : PROTECTED_SACL_SECURITY_INFORMATION) end hr = SetNamedSecurityInfoW(path.to_wstring, type, security_information, owner, group, dacl, sacl) if hr != ERROR_SUCCESS Chef::ReservedNames::Win32::Error.raise! end end def self.set_security_access_mask(security_information) result = FFI::Buffer.new(:long) SetSecurityAccessMask(security_information, result) result.read_long end def set_security_descriptor_dacl(security_descriptor, acl, defaulted = false, present = nil) security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) acl = acl.pointer if acl.respond_to?(:pointer) present = !security_descriptor.null? if present == nil unless SetSecurityDescriptorDacl(security_descriptor, present, acl, defaulted) Chef::ReservedNames::Win32::Error.raise! end end def self.set_security_descriptor_group(security_descriptor, sid, defaulted = false) security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) sid = sid.pointer if sid.respond_to?(:pointer) unless SetSecurityDescriptorGroup(security_descriptor, sid, defaulted) Chef::ReservedNames::Win32::Error.raise! end end def self.set_security_descriptor_owner(security_descriptor, sid, defaulted = false) security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) sid = sid.pointer if sid.respond_to?(:pointer) unless SetSecurityDescriptorOwner(security_descriptor, sid, defaulted) Chef::ReservedNames::Win32::Error.raise! end end def self.set_security_descriptor_sacl(security_descriptor, acl, defaulted = false, present = nil) security_descriptor = security_descriptor.pointer if security_descriptor.respond_to?(:pointer) acl = acl.pointer if acl.respond_to?(:pointer) present = !security_descriptor.null? if present == nil unless SetSecurityDescriptorSacl(security_descriptor, present, acl, defaulted) Chef::ReservedNames::Win32::Error.raise! end end def self.with_privileges(*privilege_names) # Set privileges token = open_process_token(Chef::ReservedNames::Win32::Process.get_current_process, TOKEN_READ | TOKEN_ADJUST_PRIVILEGES) old_privileges = token.enable_privileges(*privilege_names) # Let the caller do their privileged stuff begin yield ensure # Set privileges back to what they were before token.adjust_privileges(old_privileges) end end # Checks if the caller has the admin privileges in their # security token def self.has_admin_privileges? if Chef::Platform.windows_server_2003? # Admin privileges do not exist on Windows Server 2003 true else process_token = open_process_token(Chef::ReservedNames::Win32::Process.get_current_process, TOKEN_READ) elevation_result = FFI::Buffer.new(:ulong) elevation_result_size = FFI::MemoryPointer.new(:uint32) success = GetTokenInformation(process_token.handle.handle, :TokenElevation, elevation_result, 4, elevation_result_size) # Assume process is not elevated if the call fails. # Process is elevated if the result is different than 0. success && (elevation_result.read_ulong != 0) end end end end end require 'chef/win32/security/ace' require 'chef/win32/security/acl' require 'chef/win32/security/securable_object' require 'chef/win32/security/security_descriptor' require 'chef/win32/security/sid' chef-11.8.2/lib/chef/win32/api/0000755000004100000410000000000012254362222015726 5ustar www-datawww-datachef-11.8.2/lib/chef/win32/api/system.rb0000644000004100000410000002302412254362222017600 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/api' class Chef module ReservedNames::Win32 module API module System extend Chef::ReservedNames::Win32::API ############################################### # Win32 API Constants ############################################### # http://msdn.microsoft.com/en-us/library/ms724833(v=vs.85).aspx # Suite Masks # Microsoft BackOffice components are installed. VER_SUITE_BACKOFFICE = 0x00000004 # Windows Server 2003, Web Edition is installed. VER_SUITE_BLADE = 0x00000400 # Windows Server 2003, Compute Cluster Edition is installed. VER_SUITE_COMPUTE_SERVER = 0x00004000 # Windows Server 2008 Datacenter, Windows Server 2003, Datacenter Edition, or Windows 2000 Datacenter Server is installed. VER_SUITE_DATACENTER = 0x00000080 # Windows Server 2008 Enterprise, Windows Server 2003, Enterprise Edition, or Windows 2000 Advanced Server is installed. Refer to the Remarks section for more information about this bit flag. VER_SUITE_ENTERPRISE = 0x00000002 # Windows XP Embedded is installed. VER_SUITE_EMBEDDEDNT = 0x00000040 # Windows Vista Home Premium, Windows Vista Home Basic, or Windows XP Home Edition is installed. VER_SUITE_PERSONAL = 0x00000200 # Remote Desktop is supported, but only one interactive session is supported. This value is set unless the system is running in application server mode. VER_SUITE_SINGLEUSERTS = 0x00000100 # Microsoft Small Business Server was once installed on the system, but may have been upgraded to another version of Windows. Refer to the Remarks section for more information about this bit flag. VER_SUITE_SMALLBUSINESS = 0x00000001 # Microsoft Small Business Server is installed with the restrictive client license in force. Refer to the Remarks section for more information about this bit flag. VER_SUITE_SMALLBUSINESS_RESTRICTED = 0x00000020 # Windows Storage Server 2003 R2 or Windows Storage Server 2003is installed. VER_SUITE_STORAGE_SERVER = 0x00002000 # Terminal Services is installed. This value is always set. # If VER_SUITE_TERMINAL is set but VER_SUITE_SINGLEUSERTS is not set, the system is running in application server mode. VER_SUITE_TERMINAL = 0x00000010 # Windows Home Server is installed. VER_SUITE_WH_SERVER = 0x00008000 # Product Type # The system is a domain controller and the operating system is Windows Server 2008 R2, Windows Server 2008, Windows Server 2003, or Windows 2000 Server. VER_NT_DOMAIN_CONTROLLER = 0x0000002 # The operating system is Windows Server 2008 R2, Windows Server 2008, Windows Server 2003, or Windows 2000 Server. # Note that a server that is also a domain controller is reported as VER_NT_DOMAIN_CONTROLLER, not VER_NT_SERVER. VER_NT_SERVER = 0x0000003 # The operating system is Windows 7, Windows Vista, Windows XP Professional, Windows XP Home Edition, or Windows 2000 Professional. VER_NT_WORKSTATION = 0x0000001 # Product Info # http://msdn.microsoft.com/en-us/library/ms724358(v=vs.85).aspx PRODUCT_BUSINESS = 0x00000006 # Business PRODUCT_BUSINESS_N = 0x00000010 # Business N PRODUCT_CLUSTER_SERVER = 0x00000012 # HPC Edition PRODUCT_DATACENTER_SERVER = 0x00000008 # Server Datacenter (full installation) PRODUCT_DATACENTER_SERVER_CORE = 0x0000000C # Server Datacenter (core installation) PRODUCT_DATACENTER_SERVER_CORE_V = 0x00000027 # Server Datacenter without Hyper-V (core installation) PRODUCT_DATACENTER_SERVER_V = 0x00000025 # Server Datacenter without Hyper-V (full installation) PRODUCT_ENTERPRISE = 0x00000004 # Enterprise PRODUCT_ENTERPRISE_E = 0x00000046 # Not supported PRODUCT_ENTERPRISE_N = 0x0000001B # Enterprise N PRODUCT_ENTERPRISE_SERVER = 0x0000000A # Server Enterprise (full installation) PRODUCT_ENTERPRISE_SERVER_CORE = 0x0000000E # Server Enterprise (core installation) PRODUCT_ENTERPRISE_SERVER_CORE_V = 0x00000029 # Server Enterprise without Hyper-V (core installation) PRODUCT_ENTERPRISE_SERVER_IA64 = 0x0000000F # Server Enterprise for Itanium-based Systems PRODUCT_ENTERPRISE_SERVER_V = 0x00000026 # Server Enterprise without Hyper-V (full installation) PRODUCT_HOME_BASIC = 0x00000002 # Home Basic PRODUCT_HOME_BASIC_E = 0x00000043 # Not supported PRODUCT_HOME_BASIC_N = 0x00000005 # Home Basic N PRODUCT_HOME_PREMIUM = 0x00000003 # Home Premium PRODUCT_HOME_PREMIUM_E = 0x00000044 # Not supported PRODUCT_HOME_PREMIUM_N = 0x0000001A # Home Premium N PRODUCT_HYPERV = 0x0000002A # Microsoft Hyper-V Server PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT = 0x0000001E # Windows Essential Business Server Management Server PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING = 0x00000020 # Windows Essential Business Server Messaging Server PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY = 0x0000001F # Windows Essential Business Server Security Server PRODUCT_PROFESSIONAL = 0x00000030 # Professional PRODUCT_PROFESSIONAL_E = 0x00000045 # Not supported PRODUCT_PROFESSIONAL_N = 0x00000031 # Professional N PRODUCT_SERVER_FOR_SMALLBUSINESS = 0x00000018 # Windows Server 2008 for Windows Essential Server Solutions PRODUCT_SERVER_FOR_SMALLBUSINESS_V = 0x00000023 # Windows Server 2008 without Hyper-V for Windows Essential Server Solutions PRODUCT_SERVER_FOUNDATION = 0x00000021 # Server Foundation PRODUCT_HOME_PREMIUM_SERVER = 0x00000022 # Windows Home Server 2011 PRODUCT_SB_SOLUTION_SERVER = 0x00000032 # Windows Small Business Server 2011 Essentials PRODUCT_HOME_SERVER = 0x00000013 # Windows Storage Server 2008 R2 Essentials PRODUCT_SMALLBUSINESS_SERVER = 0x00000009 # Windows Small Business Server PRODUCT_SOLUTION_EMBEDDEDSERVER = 0x00000038 # Windows MultiPoint Server PRODUCT_STANDARD_SERVER = 0x00000007 # Server Standard (full installation) PRODUCT_STANDARD_SERVER_CORE = 0x0000000D # Server Standard (core installation) PRODUCT_STANDARD_SERVER_CORE_V = 0x00000028 # Server Standard without Hyper-V (core installation) PRODUCT_STANDARD_SERVER_V = 0x00000024 # Server Standard without Hyper-V (full installation) PRODUCT_STARTER = 0x0000000B # Starter PRODUCT_STARTER_E = 0x00000042 # Not supported PRODUCT_STARTER_N = 0x0000002F # Starter N PRODUCT_STORAGE_ENTERPRISE_SERVER = 0x00000017 # Storage Server Enterprise PRODUCT_STORAGE_EXPRESS_SERVER = 0x00000014 # Storage Server Express PRODUCT_STORAGE_STANDARD_SERVER = 0x00000015 # Storage Server Standard PRODUCT_STORAGE_WORKGROUP_SERVER = 0x00000016 # Storage Server Workgroup PRODUCT_UNDEFINED = 0x00000000 # An unknown product PRODUCT_ULTIMATE = 0x00000001 # Ultimate PRODUCT_ULTIMATE_E = 0x00000047 # Not supported PRODUCT_ULTIMATE_N = 0x0000001C # Ultimate N PRODUCT_WEB_SERVER = 0x00000011 # Web Server (full installation) PRODUCT_WEB_SERVER_CORE = 0x0000001D # Web Server (core installation) # GetSystemMetrics # The build number if the system is Windows Server 2003 R2; otherwise, 0. SM_SERVERR2 = 89 ############################################### # Win32 API Bindings ############################################### ffi_lib 'kernel32', 'user32' class OSVERSIONINFOEX < FFI::Struct layout :dw_os_version_info_size, :DWORD, :dw_major_version, :DWORD, :dw_minor_version, :DWORD, :dw_build_number, :DWORD, :dw_platform_id, :DWORD, :sz_csd_version, [:BYTE, 256], :w_service_pack_major, :WORD, :w_service_pack_minor, :WORD, :w_suite_mask, :WORD, :w_product_type, :BYTE, :w_reserved, :BYTE end =begin BOOL WINAPI CloseHandle( __in HANDLE hObject ); =end safe_attach_function :CloseHandle, [ :HANDLE ], :BOOL =begin DWORD WINAPI GetVersion(void); =end safe_attach_function :GetVersion, [], :DWORD =begin BOOL WINAPI GetVersionEx( __inout LPOSVERSIONINFO lpVersionInfo ); =end safe_attach_function :GetVersionExW, [:pointer], :BOOL safe_attach_function :GetVersionExA, [:pointer], :BOOL =begin BOOL WINAPI GetProductInfo( __in DWORD dwOSMajorVersion, __in DWORD dwOSMinorVersion, __in DWORD dwSpMajorVersion, __in DWORD dwSpMinorVersion, __out PDWORD pdwReturnedProductType ); =end safe_attach_function :GetProductInfo, [:DWORD, :DWORD, :DWORD, :DWORD, :PDWORD], :BOOL =begin int WINAPI GetSystemMetrics( __in int nIndex ); =end safe_attach_function :GetSystemMetrics, [:int], :int end end end end chef-11.8.2/lib/chef/win32/api/process.rb0000644000004100000410000000242412254362222017733 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/api' class Chef module ReservedNames::Win32 module API module Process extend Chef::ReservedNames::Win32::API ############################################### # Win32 API Bindings ############################################### ffi_lib 'kernel32' safe_attach_function :GetCurrentProcess, [], :HANDLE safe_attach_function :GetProcessHandleCount, [ :HANDLE, :LPDWORD ], :BOOL safe_attach_function :GetProcessId, [ :HANDLE ], :DWORD safe_attach_function :CloseHandle, [ :HANDLE ], :BOOL end end end end chef-11.8.2/lib/chef/win32/api/psapi.rb0000644000004100000410000000307212254362222017371 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/api' class Chef module ReservedNames::Win32 module API module PSAPI extend Chef::ReservedNames::Win32::API ############################################### # Win32 API Bindings ############################################### class PROCESS_MEMORY_COUNTERS < FFI::Struct layout :cb, :DWORD, :PageFaultCount, :DWORD, :PeakWorkingSetSize, :SIZE_T, :WorkingSetSize, :SIZE_T, :QuotaPeakPagedPoolUsage, :SIZE_T, :QuotaPagedPoolUsage, :SIZE_T, :QuotaPeakNonPagedPoolUsage, :SIZE_T, :QuotaNonPagedPoolUsage, :SIZE_T, :PagefileUsage, :SIZE_T, :PeakPagefileUsage, :SIZE_T end ffi_lib 'psapi' safe_attach_function :GetProcessMemoryInfo, [ :HANDLE, :pointer, :DWORD ], :BOOL end end end end chef-11.8.2/lib/chef/win32/api/memory.rb0000644000004100000410000000565712254362222017600 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/api' class Chef module ReservedNames::Win32 module API module Memory extend Chef::ReservedNames::Win32::API ############################################### # Win32 API Constants ############################################### LMEM_FIXED = 0x0000 LMEM_MOVEABLE = 0x0002 LMEM_NOCOMPACT = 0x0010 LMEM_NODISCARD = 0x0020 LMEM_ZEROINIT = 0x0040 LMEM_MODIFY = 0x0080 LMEM_DISCARDABLE = 0x0F00 LMEM_VALID_FLAGS = 0x0F72 LMEM_INVALID_HANDLE = 0x8000 LHND = LMEM_MOVEABLE | LMEM_ZEROINIT LPTR = LMEM_FIXED | LMEM_ZEROINIT NONZEROLHND = LMEM_MOVEABLE NONZEROLPTR = LMEM_FIXED LMEM_DISCARDED = 0x4000 LMEM_LOCKCOUNT = 0x00FF ############################################### # Win32 API Bindings ############################################### ffi_lib 'kernel32' =begin HLOCAL WINAPI LocalAlloc( __in UINT uFlags, __in SIZE_T uBytes ); =end safe_attach_function :LocalAlloc, [ :UINT, :SIZE_T ], :pointer =begin UINT WINAPI LocalFlags( __in HLOCAL hMem ); =end safe_attach_function :LocalFlags, [ :pointer ], :UINT =begin HLOCAL WINAPI LocalFree( __in HLOCAL hMem ); =end safe_attach_function :LocalFree, [ :pointer ], :pointer =begin HLOCAL WINAPI LocalReAlloc( __in HLOCAL hMem, __in SIZE_T uBytes, __in UINT uFlags ); =end safe_attach_function :LocalReAlloc, [ :pointer, :SIZE_T, :UINT ], :pointer =begin UINT WINAPI LocalSize( __in HLOCAL hMem ); =end safe_attach_function :LocalSize, [ :pointer ], :SIZE_T ############################################### # FFI API Bindings ############################################### ffi_lib FFI::Library::LIBC safe_attach_function :malloc, [:size_t], :pointer safe_attach_function :calloc, [:size_t], :pointer safe_attach_function :realloc, [:pointer, :size_t], :pointer safe_attach_function :free, [:pointer], :void safe_attach_function :memcpy, [:pointer, :pointer, :size_t], :pointer end end end end chef-11.8.2/lib/chef/win32/api/security.rb0000644000004100000410000004173012254362222020127 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/api' class Chef module ReservedNames::Win32 module API module Security extend Chef::ReservedNames::Win32::API ############################################### # Win32 API Constants ############################################### # ACE_HEADER AceType ACCESS_MIN_MS_ACE_TYPE = 0x0 ACCESS_ALLOWED_ACE_TYPE = 0x0 ACCESS_DENIED_ACE_TYPE = 0x1 SYSTEM_AUDIT_ACE_TYPE = 0x2 SYSTEM_ALARM_ACE_TYPE = 0x3 ACCESS_MAX_MS_V2_ACE_TYPE = 0x3 ACCESS_ALLOWED_COMPOUND_ACE_TYPE = 0x4 ACCESS_MAX_MS_V3_ACE_TYPE = 0x4 ACCESS_MIN_MS_OBJECT_ACE_TYPE = 0x5 ACCESS_ALLOWED_OBJECT_ACE_TYPE = 0x5 ACCESS_DENIED_OBJECT_ACE_TYPE = 0x6 SYSTEM_AUDIT_OBJECT_ACE_TYPE = 0x7 SYSTEM_ALARM_OBJECT_ACE_TYPE = 0x8 ACCESS_MAX_MS_OBJECT_ACE_TYPE = 0x8 ACCESS_MAX_MS_V4_ACE_TYPE = 0x8 ACCESS_MAX_MS_ACE_TYPE = 0x8 ACCESS_ALLOWED_CALLBACK_ACE_TYPE = 0x9 ACCESS_DENIED_CALLBACK_ACE_TYPE = 0xA ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE = 0xB ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE = 0xC SYSTEM_AUDIT_CALLBACK_ACE_TYPE = 0xD SYSTEM_ALARM_CALLBACK_ACE_TYPE = 0xE SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE = 0xF SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE = 0x10 SYSTEM_MANDATORY_LABEL_ACE_TYPE = 0x11 ACCESS_MAX_MS_V5_ACE_TYPE = 0x11 # ACE_HEADER AceFlags OBJECT_INHERIT_ACE = 0x1 CONTAINER_INHERIT_ACE = 0x2 NO_PROPAGATE_INHERIT_ACE = 0x4 INHERIT_ONLY_ACE = 0x8 INHERITED_ACE = 0x10 VALID_INHERIT_FLAGS = 0x1F SUCCESSFUL_ACCESS_ACE_FLAG = 0x40 FAILED_ACCESS_ACE_FLAG = 0x80 # SECURITY_INFORMATION flags (DWORD) OWNER_SECURITY_INFORMATION = 0x01 GROUP_SECURITY_INFORMATION = 0x02 DACL_SECURITY_INFORMATION = 0x04 SACL_SECURITY_INFORMATION = 0x08 LABEL_SECURITY_INFORMATION = 0x10 UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000 UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000 PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000 PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000 # SECURITY_DESCRIPTOR_REVISION SECURITY_DESCRIPTOR_REVISION = 1 SECURITY_DESCRIPTOR_REVISION1 = 1 # SECURITY_DESCRIPTOR_CONTROL SE_OWNER_DEFAULTED = 0x0001 SE_GROUP_DEFAULTED = 0x0002 SE_DACL_PRESENT = 0x0004 SE_DACL_DEFAULTED = 0x0008 SE_SACL_PRESENT = 0x0010 SE_SACL_DEFAULTED = 0x0020 SE_DACL_AUTO_INHERIT_REQ = 0x0100 SE_SACL_AUTO_INHERIT_REQ = 0x0200 SE_DACL_AUTO_INHERITED = 0x0400 SE_SACL_AUTO_INHERITED = 0x0800 SE_DACL_PROTECTED = 0x1000 SE_SACL_PROTECTED = 0x2000 SE_RM_CONTROL_VALID = 0x4000 SE_SELF_RELATIVE = 0x8000 # ACCESS_RIGHTS_MASK # Generic Access Rights GENERIC_READ = 0x80000000 GENERIC_WRITE = 0x40000000 GENERIC_EXECUTE = 0x20000000 GENERIC_ALL = 0x10000000 # Standard Access Rights DELETE = 0x00010000 READ_CONTROL = 0x00020000 WRITE_DAC = 0x00040000 WRITE_OWNER = 0x00080000 SYNCHRONIZE = 0x00100000 STANDARD_RIGHTS_REQUIRED = 0x000F0000 STANDARD_RIGHTS_READ = READ_CONTROL STANDARD_RIGHTS_WRITE = READ_CONTROL STANDARD_RIGHTS_EXECUTE = READ_CONTROL STANDARD_RIGHTS_ALL = 0x001F0000 SPECIFIC_RIGHTS_ALL = 0x0000FFFF # Access System Security Right ACCESS_SYSTEM_SECURITY = 0x01000000 # File/Directory Specific Rights FILE_READ_DATA = 0x0001 FILE_LIST_DIRECTORY = 0x0001 FILE_WRITE_DATA = 0x0002 FILE_ADD_FILE = 0x0002 FILE_APPEND_DATA = 0x0004 FILE_ADD_SUBDIRECTORY = 0x0004 FILE_CREATE_PIPE_INSTANCE = 0x0004 FILE_READ_EA = 0x0008 FILE_WRITE_EA = 0x0010 FILE_EXECUTE = 0x0020 FILE_TRAVERSE = 0x0020 FILE_DELETE_CHILD = 0x0040 FILE_READ_ATTRIBUTES = 0x0080 FILE_WRITE_ATTRIBUTES = 0x0100 FILE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF FILE_GENERIC_READ = STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE FILE_GENERIC_WRITE = STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE FILE_GENERIC_EXECUTE = STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE # Access Token Rights (for OpenProcessToken) # Access Rights for Access-Token Objects (used in OpenProcessToken) TOKEN_ASSIGN_PRIMARY = 0x0001 TOKEN_DUPLICATE = 0x0002 TOKEN_IMPERSONATE = 0x0004 TOKEN_QUERY = 0x0008 TOKEN_QUERY_SOURCE = 0x0010 TOKEN_ADJUST_PRIVILEGES = 0x0020 TOKEN_ADJUST_GROUPS = 0x0040 TOKEN_ADJUST_DEFAULT = 0x0080 TOKEN_ADJUST_SESSIONID = 0x0100 TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY) TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID) # AdjustTokenPrivileges SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001 SE_PRIVILEGE_ENABLED = 0x00000002 SE_PRIVILEGE_REMOVED = 0X00000004 SE_PRIVILEGE_USED_FOR_ACCESS = 0x80000000 SE_PRIVILEGE_VALID_ATTRIBUTES = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED | SE_PRIVILEGE_USED_FOR_ACCESS # Minimum size of a SECURITY_DESCRIPTOR. TODO: this is probably platform dependent. # Make it work on 64 bit. SECURITY_DESCRIPTOR_MIN_LENGTH = 20 # ACL revisions ACL_REVISION = 2 ACL_REVISION_DS = 4 ACL_REVISION1 = 1 ACL_REVISION2 = 2 ACL_REVISION3 = 3 ACL_REVISION4 = 4 MIN_ACL_REVISION = ACL_REVISION2 MAX_ACL_REVISION = ACL_REVISION4 MAXDWORD = 0xffffffff ############################################### # Win32 API Bindings ############################################### SE_OBJECT_TYPE = enum :SE_OBJECT_TYPE, [ :SE_UNKNOWN_OBJECT_TYPE, :SE_FILE_OBJECT, :SE_SERVICE, :SE_PRINTER, :SE_REGISTRY_KEY, :SE_LMSHARE, :SE_KERNEL_OBJECT, :SE_WINDOW_OBJECT, :SE_DS_OBJECT, :SE_DS_OBJECT_ALL, :SE_PROVIDER_DEFINED_OBJECT, :SE_WMIGUID_OBJECT, :SE_REGISTRY_WOW64_32KEY ] SID_NAME_USE = enum :SID_NAME_USE, [ :SidTypeUser, 1, :SidTypeGroup, :SidTypeDomain, :SidTypeAlias, :SidTypeWellKnownGroup, :SidTypeDeletedAccount, :SidTypeInvalid, :SidTypeUnknown, :SidTypeComputer, :SidTypeLabel ] TOKEN_INFORMATION_CLASS = enum :TOKEN_INFORMATION_CLASS, [ :TokenUser, 1, :TokenGroups, :TokenPrivileges, :TokenOwner, :TokenPrimaryGroup, :TokenDefaultDacl, :TokenSource, :TokenType, :TokenImpersonationLevel, :TokenStatistics, :TokenRestrictedSids, :TokenSessionId, :TokenGroupsAndPrivileges, :TokenSessionReference, :TokenSandBoxInert, :TokenAuditPolicy, :TokenOrigin, :TokenElevationType, :TokenLinkedToken, :TokenElevation, :TokenHasRestrictions, :TokenAccessInformation, :TokenVirtualizationAllowed, :TokenVirtualizationEnabled, :TokenIntegrityLevel, :TokenUIAccess, :TokenMandatoryPolicy, :TokenLogonSid, :TokenIsAppContainer, :TokenCapabilities, :TokenAppContainerSid, :TokenAppContainerNumber, :TokenUserClaimAttributes, :TokenDeviceClaimAttributes, :TokenRestrictedUserClaimAttributes, :TokenRestrictedDeviceClaimAttributes, :TokenDeviceGroups, :TokenRestrictedDeviceGroups, :TokenSecurityAttributes, :TokenIsRestricted, :MaxTokenInfoClass ] # SECURITY_DESCRIPTOR is an opaque structure whose contents can vary. Pass the # pointer around and free it with LocalFree. # http://msdn.microsoft.com/en-us/library/windows/desktop/aa379561(v=vs.85).aspx # SID is an opaque structure. Pass the pointer around. # ACL type is a header with some information, followed by an array of ACEs # http://msdn.microsoft.com/en-us/library/windows/desktop/aa374931(v=VS.85).aspx class ACLStruct < FFI::Struct layout :AclRevision, :uchar, :Sbzl, :uchar, :AclSize, :ushort, :AceCount, :ushort, :Sbz2, :ushort end class ACE_HEADER < FFI::Struct layout :AceType, :uchar, :AceFlags, :uchar, :AceSize, :ushort end class ACE_WITH_MASK_AND_SID < FFI::Struct layout :AceType, :uchar, :AceFlags, :uchar, :AceSize, :ushort, :Mask, :uint32, :SidStart, :uint32 # The AceTypes this structure supports def self.supports?(ace_type) [ ACCESS_ALLOWED_ACE_TYPE, ACCESS_DENIED_ACE_TYPE, SYSTEM_AUDIT_ACE_TYPE, SYSTEM_ALARM_ACE_TYPE ].include?(ace_type) end end class LUID < FFI::Struct layout :LowPart, :DWORD, :HighPart, :LONG end class LUID_AND_ATTRIBUTES < FFI::Struct layout :Luid, LUID, :Attributes, :DWORD end class TOKEN_PRIVILEGES < FFI::Struct layout :PrivilegeCount, :DWORD, :Privileges, LUID_AND_ATTRIBUTES def self.size_with_privileges(num_privileges) offset_of(:Privileges) + LUID_AND_ATTRIBUTES.size*num_privileges end def size_with_privileges TOKEN_PRIVILEGES.size_with_privileges(self[:PrivilegeCount]) end def privilege(index) LUID_AND_ATTRIBUTES.new(pointer + offset_of(:Privileges) + (index * LUID_AND_ATTRIBUTES.size)) end end ffi_lib "advapi32" safe_attach_function :AddAce, [ :pointer, :DWORD, :DWORD, :LPVOID, :DWORD ], :BOOL safe_attach_function :AddAccessAllowedAce, [ :pointer, :DWORD, :DWORD, :pointer ], :BOOL safe_attach_function :AddAccessAllowedAceEx, [ :pointer, :DWORD, :DWORD, :DWORD, :pointer ], :BOOL safe_attach_function :AddAccessDeniedAce, [ :pointer, :DWORD, :DWORD, :pointer ], :BOOL safe_attach_function :AddAccessDeniedAceEx, [ :pointer, :DWORD, :DWORD, :DWORD, :pointer ], :BOOL safe_attach_function :AdjustTokenPrivileges, [ :HANDLE, :BOOL, :pointer, :DWORD, :pointer, :PDWORD ], :BOOL safe_attach_function :ConvertSidToStringSidA, [ :pointer, :pointer ], :BOOL safe_attach_function :ConvertStringSidToSidW, [ :pointer, :pointer ], :BOOL safe_attach_function :DeleteAce, [ :pointer, :DWORD ], :BOOL safe_attach_function :EqualSid, [ :pointer, :pointer ], :BOOL safe_attach_function :FreeSid, [ :pointer ], :pointer safe_attach_function :GetAce, [ :pointer, :DWORD, :pointer ], :BOOL safe_attach_function :GetLengthSid, [ :pointer ], :DWORD safe_attach_function :GetNamedSecurityInfoW, [ :LPWSTR, :SE_OBJECT_TYPE, :DWORD, :pointer, :pointer, :pointer, :pointer, :pointer ], :DWORD safe_attach_function :GetSecurityDescriptorControl, [ :pointer, :PWORD, :LPDWORD], :BOOL safe_attach_function :GetSecurityDescriptorDacl, [ :pointer, :LPBOOL, :pointer, :LPBOOL ], :BOOL safe_attach_function :GetSecurityDescriptorGroup, [ :pointer, :pointer, :LPBOOL], :BOOL safe_attach_function :GetSecurityDescriptorOwner, [ :pointer, :pointer, :LPBOOL], :BOOL safe_attach_function :GetSecurityDescriptorSacl, [ :pointer, :LPBOOL, :pointer, :LPBOOL ], :BOOL safe_attach_function :InitializeAcl, [ :pointer, :DWORD, :DWORD ], :BOOL safe_attach_function :InitializeSecurityDescriptor, [ :pointer, :DWORD ], :BOOL safe_attach_function :IsValidAcl, [ :pointer ], :BOOL safe_attach_function :IsValidSecurityDescriptor, [ :pointer ], :BOOL safe_attach_function :IsValidSid, [ :pointer ], :BOOL safe_attach_function :LookupAccountNameW, [ :LPCWSTR, :LPCWSTR, :pointer, :LPDWORD, :LPWSTR, :LPDWORD, :pointer ], :BOOL safe_attach_function :LookupAccountSidW, [ :LPCWSTR, :pointer, :LPWSTR, :LPDWORD, :LPWSTR, :LPDWORD, :pointer ], :BOOL safe_attach_function :LookupPrivilegeNameW, [ :LPCWSTR, :PLUID, :LPWSTR, :LPDWORD ], :BOOL safe_attach_function :LookupPrivilegeDisplayNameW, [ :LPCWSTR, :LPCWSTR, :LPWSTR, :LPDWORD, :LPDWORD ], :BOOL safe_attach_function :LookupPrivilegeValueW, [ :LPCWSTR, :LPCWSTR, :PLUID ], :BOOL safe_attach_function :MakeAbsoluteSD, [ :pointer, :pointer, :LPDWORD, :pointer, :LPDWORD, :pointer, :LPDWORD, :pointer, :LPDWORD, :pointer, :LPDWORD], :BOOL safe_attach_function :OpenProcessToken, [ :HANDLE, :DWORD, :PHANDLE ], :BOOL safe_attach_function :QuerySecurityAccessMask, [ :DWORD, :LPDWORD ], :void safe_attach_function :SetFileSecurityW, [ :LPWSTR, :DWORD, :pointer ], :BOOL safe_attach_function :SetNamedSecurityInfoW, [ :LPWSTR, :SE_OBJECT_TYPE, :DWORD, :pointer, :pointer, :pointer, :pointer ], :DWORD safe_attach_function :SetSecurityAccessMask, [ :DWORD, :LPDWORD ], :void safe_attach_function :SetSecurityDescriptorDacl, [ :pointer, :BOOL, :pointer, :BOOL ], :BOOL safe_attach_function :SetSecurityDescriptorGroup, [ :pointer, :pointer, :BOOL ], :BOOL safe_attach_function :SetSecurityDescriptorOwner, [ :pointer, :pointer, :BOOL ], :BOOL safe_attach_function :SetSecurityDescriptorSacl, [ :pointer, :BOOL, :pointer, :BOOL ], :BOOL safe_attach_function :GetTokenInformation, [ :HANDLE, :TOKEN_INFORMATION_CLASS, :pointer, :DWORD, :PDWORD ], :BOOL end end end end chef-11.8.2/lib/chef/win32/api/synchronization.rb0000644000004100000410000000510312254362222021513 0ustar www-datawww-data# # Author:: Serdar Sutay () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/api' class Chef module ReservedNames::Win32 module API module Synchronization extend Chef::ReservedNames::Win32::API ffi_lib 'kernel32' # Constant synchronization functions use to indicate wait # forever. INFINITE = 0xFFFFFFFF # Return codes # http://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx WAIT_FAILED = 0xFFFFFFFF WAIT_TIMEOUT = 0x00000102 WAIT_OBJECT_0 = 0x00000000 WAIT_ABANDONED = 0x00000080 # Security and access rights for synchronization objects # http://msdn.microsoft.com/en-us/library/windows/desktop/ms686670(v=vs.85).aspx DELETE = 0x00010000 READ_CONTROL = 0x00020000 SYNCHRONIZE = 0x00100000 WRITE_DAC = 0x00040000 WRITE_OWNER = 0x00080000 # Mutex specific rights MUTEX_ALL_ACCESS = 0x001F0001 MUTEX_MODIFY_STATE = 0x00000001 =begin HANDLE WINAPI CreateMutex( _In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes, _In_ BOOL bInitialOwner, _In_opt_ LPCTSTR lpName ); =end safe_attach_function :CreateMutexW, [ :LPSECURITY_ATTRIBUTES, :BOOL, :LPCTSTR ], :HANDLE safe_attach_function :CreateMutexA, [ :LPSECURITY_ATTRIBUTES, :BOOL, :LPCTSTR ], :HANDLE =begin DWORD WINAPI WaitForSingleObject( _In_ HANDLE hHandle, _In_ DWORD dwMilliseconds ); =end safe_attach_function :WaitForSingleObject, [ :HANDLE, :DWORD ], :DWORD =begin BOOL WINAPI ReleaseMutex( _In_ HANDLE hMutex ); =end safe_attach_function :ReleaseMutex, [ :HANDLE ], :BOOL =begin HANDLE WINAPI OpenMutex( _In_ DWORD dwDesiredAccess, _In_ BOOL bInheritHandle, _In_ LPCTSTR lpName ); =end safe_attach_function :OpenMutexW, [ :DWORD, :BOOL, :LPCTSTR ], :HANDLE safe_attach_function :OpenMutexA, [ :DWORD, :BOOL, :LPCTSTR ], :HANDLE end end end end chef-11.8.2/lib/chef/win32/api/file.rb0000644000004100000410000004647712254362222017214 0ustar www-datawww-data# # Author:: Seth Chisamore () # Author:: Mark Mzyk () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/api' require 'chef/win32/api/security' require 'chef/win32/api/system' class Chef module ReservedNames::Win32 module API module File extend Chef::ReservedNames::Win32::API include Chef::ReservedNames::Win32::API::Security include Chef::ReservedNames::Win32::API::System ############################################### # Win32 API Constants ############################################### FILE_ATTRIBUTE_READONLY = 0x00000001 FILE_ATTRIBUTE_HIDDEN = 0x00000002 FILE_ATTRIBUTE_SYSTEM = 0x00000004 FILE_ATTRIBUTE_DIRECTORY = 0x00000010 FILE_ATTRIBUTE_ARCHIVE = 0x00000020 FILE_ATTRIBUTE_DEVICE = 0x00000040 FILE_ATTRIBUTE_NORMAL = 0x00000080 FILE_ATTRIBUTE_TEMPORARY = 0x00000100 FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200 FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400 FILE_ATTRIBUTE_COMPRESSED = 0x00000800 FILE_ATTRIBUTE_OFFLINE = 0x00001000 FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000 FILE_ATTRIBUTE_ENCRYPTED = 0x00004000 FILE_ATTRIBUTE_VIRTUAL = 0x00010000 INVALID_FILE_ATTRIBUTES = 0xFFFFFFFF FILE_FLAG_WRITE_THROUGH = 0x80000000 FILE_FLAG_OVERLAPPED = 0x40000000 FILE_FLAG_NO_BUFFERING = 0x20000000 FILE_FLAG_RANDOM_ACCESS = 0x10000000 FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000 FILE_FLAG_DELETE_ON_CLOSE = 0x04000000 FILE_FLAG_BACKUP_SEMANTICS = 0x02000000 FILE_FLAG_POSIX_SEMANTICS = 0x01000000 FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000 FILE_FLAG_OPEN_NO_RECALL = 0x00100000 FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000 INVALID_HANDLE_VALUE = 0xFFFFFFFF MAX_PATH = 260 SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1 FILE_NAME_NORMALIZED = 0x0 FILE_NAME_OPENED = 0x8 # TODO add the rest of these CONSTS FILE_SHARE_READ = 0x00000001 OPEN_EXISTING = 3 # DeviceIoControl control codes # ----------------------------- FILE_DEVICE_BEEP = 0x00000001 FILE_DEVICE_CD_ROM = 0x00000002 FILE_DEVICE_CD_ROM_FILE_SYSTEM = 0x00000003 FILE_DEVICE_CONTROLLER = 0x00000004 FILE_DEVICE_DATALINK = 0x00000005 FILE_DEVICE_DFS = 0x00000006 FILE_DEVICE_DISK = 0x00000007 FILE_DEVICE_DISK_FILE_SYSTEM = 0x00000008 FILE_DEVICE_FILE_SYSTEM = 0x00000009 FILE_DEVICE_INPORT_PORT = 0x0000000a FILE_DEVICE_KEYBOARD = 0x0000000b FILE_DEVICE_MAILSLOT = 0x0000000c FILE_DEVICE_MIDI_IN = 0x0000000d FILE_DEVICE_MIDI_OUT = 0x0000000e FILE_DEVICE_MOUSE = 0x0000000f FILE_DEVICE_MULTI_UNC_PROVIDER = 0x00000010 FILE_DEVICE_NAMED_PIPE = 0x00000011 FILE_DEVICE_NETWORK = 0x00000012 FILE_DEVICE_NETWORK_BROWSER = 0x00000013 FILE_DEVICE_NETWORK_FILE_SYSTEM = 0x00000014 FILE_DEVICE_NULL = 0x00000015 FILE_DEVICE_PARALLEL_PORT = 0x00000016 FILE_DEVICE_PHYSICAL_NETCARD = 0x00000017 FILE_DEVICE_PRINTER = 0x00000018 FILE_DEVICE_SCANNER = 0x00000019 FILE_DEVICE_SERIAL_MOUSE_PORT = 0x0000001a FILE_DEVICE_SERIAL_PORT = 0x0000001b FILE_DEVICE_SCREEN = 0x0000001c FILE_DEVICE_SOUND = 0x0000001d FILE_DEVICE_STREAMS = 0x0000001e FILE_DEVICE_TAPE = 0x0000001f FILE_DEVICE_TAPE_FILE_SYSTEM = 0x00000020 FILE_DEVICE_TRANSPORT = 0x00000021 FILE_DEVICE_UNKNOWN = 0x00000022 FILE_DEVICE_VIDEO = 0x00000023 FILE_DEVICE_VIRTUAL_DISK = 0x00000024 FILE_DEVICE_WAVE_IN = 0x00000025 FILE_DEVICE_WAVE_OUT = 0x00000026 FILE_DEVICE_8042_PORT = 0x00000027 FILE_DEVICE_NETWORK_REDIRECTOR = 0x00000028 FILE_DEVICE_BATTERY = 0x00000029 FILE_DEVICE_BUS_EXTENDER = 0x0000002a FILE_DEVICE_MODEM = 0x0000002b FILE_DEVICE_VDM = 0x0000002c FILE_DEVICE_MASS_STORAGE = 0x0000002d FILE_DEVICE_SMB = 0x0000002e FILE_DEVICE_KS = 0x0000002f FILE_DEVICE_CHANGER = 0x00000030 FILE_DEVICE_SMARTCARD = 0x00000031 FILE_DEVICE_ACPI = 0x00000032 FILE_DEVICE_DVD = 0x00000033 FILE_DEVICE_FULLSCREEN_VIDEO = 0x00000034 FILE_DEVICE_DFS_FILE_SYSTEM = 0x00000035 FILE_DEVICE_DFS_VOLUME = 0x00000036 FILE_DEVICE_SERENUM = 0x00000037 FILE_DEVICE_TERMSRV = 0x00000038 FILE_DEVICE_KSEC = 0x00000039 FILE_DEVICE_FIPS = 0x0000003A FILE_DEVICE_INFINIBAND = 0x0000003B FILE_DEVICE_VMBUS = 0x0000003E FILE_DEVICE_CRYPT_PROVIDER = 0x0000003F FILE_DEVICE_WPD = 0x00000040 FILE_DEVICE_BLUETOOTH = 0x00000041 FILE_DEVICE_MT_COMPOSITE = 0x00000042 FILE_DEVICE_MT_TRANSPORT = 0x00000043 FILE_DEVICE_BIOMETRIC = 0x00000044 FILE_DEVICE_PMI = 0x00000045 # Methods METHOD_BUFFERED = 0 METHOD_IN_DIRECT = 1 METHOD_OUT_DIRECT = 2 METHOD_NEITHER = 3 METHOD_DIRECT_TO_HARDWARE = METHOD_IN_DIRECT METHOD_DIRECT_FROM_HARDWARE = METHOD_OUT_DIRECT # Access FILE_ANY_ACCESS = 0 FILE_SPECIAL_ACCESS = FILE_ANY_ACCESS FILE_READ_ACCESS = 0x0001 FILE_WRITE_ACCESS = 0x0002 def self.CTL_CODE( device_type, function, method, access ) (device_type << 16) | (access << 14) | (function << 2) | method end FSCTL_GET_REPARSE_POINT = CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) # Reparse point tags IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003 IO_REPARSE_TAG_HSM = 0xC0000004 IO_REPARSE_TAG_HSM2 = 0x80000006 IO_REPARSE_TAG_SIS = 0x80000007 IO_REPARSE_TAG_WIM = 0x80000008 IO_REPARSE_TAG_CSV = 0x80000009 IO_REPARSE_TAG_DFS = 0x8000000A IO_REPARSE_TAG_SYMLINK = 0xA000000C IO_REPARSE_TAG_DFSR = 0x80000012 MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16*1024 ############################################### # Win32 API Bindings ############################################### ffi_lib 'kernel32' =begin typedef struct _FILETIME { DWORD dwLowDateTime; DWORD dwHighDateTime; } FILETIME, *PFILETIME; =end class FILETIME < FFI::Struct layout :dw_low_date_time, :DWORD, :dw_high_date_time, :DWORD end =begin typedef struct _SECURITY_ATTRIBUTES { DWORD nLength; LPVOID lpSecurityDescriptor; BOOL bInheritHandle; } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; =end class SECURITY_ATTRIBUTES < FFI::Struct layout :n_length, :DWORD, :lp_security_descriptor, :LPVOID, :b_inherit_handle, :DWORD end =begin typedef struct _WIN32_FIND_DATA { DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; DWORD dwReserved0; DWORD dwReserved1; TCHAR cFileName[MAX_PATH]; TCHAR cAlternateFileName[14]; } WIN32_FIND_DATA, *PWIN32_FIND_DATA, *LPWIN32_FIND_DATA; =end class WIN32_FIND_DATA < FFI::Struct layout :dw_file_attributes, :DWORD, :ft_creation_time, FILETIME, :ft_last_access_time, FILETIME, :ft_last_write_time, FILETIME, :n_file_size_high, :DWORD, :n_file_size_low, :DWORD, :dw_reserved_0, :DWORD, :dw_reserved_1, :DWORD, :c_file_name, [:BYTE, MAX_PATH*2], :c_alternate_file_name, [:BYTE, 14] end =begin typedef struct _BY_HANDLE_FILE_INFORMATION { DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD dwVolumeSerialNumber; DWORD nFileSizeHigh; DWORD nFileSizeLow; DWORD nNumberOfLinks; DWORD nFileIndexHigh; DWORD nFileIndexLow; } BY_HANDLE_FILE_INFORMATION, *PBY_HANDLE_FILE_INFORMATION; =end class BY_HANDLE_FILE_INFORMATION < FFI::Struct layout :dw_file_attributes, :DWORD, :ft_creation_time, FILETIME, :ft_last_access_time, FILETIME, :ft_last_write_time, FILETIME, :dw_volume_serial_number, :DWORD, :n_file_size_high, :DWORD, :n_file_size_low, :DWORD, :n_number_of_links, :DWORD, :n_file_index_high, :DWORD, :n_file_index_low, :DWORD end =begin typedef struct _REPARSE_DATA_BUFFER { ULONG ReparseTag; USHORT ReparseDataLength; USHORT Reserved; union { struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; ULONG Flags; WCHAR PathBuffer[1]; } SymbolicLinkReparseBuffer; struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; WCHAR PathBuffer[1]; } MountPointReparseBuffer; struct { UCHAR DataBuffer[1]; } GenericReparseBuffer; }; } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; =end class REPARSE_DATA_BUFFER_SYMBOLIC_LINK < FFI::Struct layout :SubstituteNameOffset, :ushort, :SubstituteNameLength, :ushort, :PrintNameOffset, :ushort, :PrintNameLength, :ushort, :Flags, :uint32, :PathBuffer, :ushort def substitute_name string_pointer = FFI::Pointer.new(pointer.address) + offset_of(:PathBuffer) + self[:SubstituteNameOffset] string_pointer.read_wstring(self[:SubstituteNameLength]/2) end def print_name string_pointer = FFI::Pointer.new(pointer.address) + offset_of(:PathBuffer) + self[:PrintNameOffset] string_pointer.read_wstring(self[:PrintNameLength]/2) end end class REPARSE_DATA_BUFFER_MOUNT_POINT < FFI::Struct layout :SubstituteNameOffset, :ushort, :SubstituteNameLength, :ushort, :PrintNameOffset, :ushort, :PrintNameLength, :ushort, :PathBuffer, :ushort def substitute_name string_pointer = FFI::Pointer.new(pointer.address) + offset_of(:PathBuffer) + self[:SubstituteNameOffset] string_pointer.read_wstring(self[:SubstituteNameLength]/2) end def print_name string_pointer = FFI::Pointer.new(pointer.address) + offset_of(:PathBuffer) + self[:PrintNameOffset] string_pointer.read_wstring(self[:PrintNameLength]/2) end end class REPARSE_DATA_BUFFER_GENERIC < FFI::Struct layout :DataBuffer, :uchar end class REPARSE_DATA_BUFFER_UNION < FFI::Union layout :SymbolicLinkReparseBuffer, REPARSE_DATA_BUFFER_SYMBOLIC_LINK, :MountPointReparseBuffer, REPARSE_DATA_BUFFER_MOUNT_POINT, :GenericReparseBuffer, REPARSE_DATA_BUFFER_GENERIC end class REPARSE_DATA_BUFFER < FFI::Struct layout :ReparseTag, :uint32, :ReparseDataLength, :ushort, :Reserved, :ushort, :ReparseBuffer, REPARSE_DATA_BUFFER_UNION def reparse_buffer if self[:ReparseTag] == IO_REPARSE_TAG_SYMLINK self[:ReparseBuffer][:SymbolicLinkReparseBuffer] elsif self[:ReparseTag] == IO_REPARSE_TAG_MOUNT_POINT self[:ReparseBuffer][:MountPointReparseBuffer] else self[:ReparseBuffer][:GenericReparseBuffer] end end end =begin HANDLE WINAPI CreateFile( __in LPCTSTR lpFileName, __in DWORD dwDesiredAccess, __in DWORD dwShareMode, __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes, __in DWORD dwCreationDisposition, __in DWORD dwFlagsAndAttributes, __in_opt HANDLE hTemplateFile ); =end safe_attach_function :CreateFileW, [:LPCTSTR, :DWORD, :DWORD, :LPSECURITY_ATTRIBUTES, :DWORD, :DWORD, :pointer], :HANDLE =begin BOOL WINAPI FindClose( __inout HANDLE hFindFile ); =end safe_attach_function :FindClose, [:HANDLE], :BOOL =begin DWORD WINAPI GetFileAttributes( __in LPCTSTR lpFileName ); =end safe_attach_function :GetFileAttributesW, [:LPCWSTR], :DWORD =begin DWORD WINAPI GetFinalPathNameByHandle( __in HANDLE hFile, __out LPTSTR lpszFilePath, __in DWORD cchFilePath, __in DWORD dwFlags ); =end safe_attach_function :GetFinalPathNameByHandleW, [:HANDLE, :LPTSTR, :DWORD, :DWORD], :DWORD =begin BOOL WINAPI GetFileInformationByHandle( __in HANDLE hFile, __out LPBY_HANDLE_FILE_INFORMATION lpFileInformation ); =end safe_attach_function :GetFileInformationByHandle, [:HANDLE, :LPBY_HANDLE_FILE_INFORMATION], :BOOL =begin HANDLE WINAPI FindFirstFile( __in LPCTSTR lpFileName, __out LPWIN32_FIND_DATA lpFindFileData ); =end safe_attach_function :FindFirstFileW, [:LPCTSTR, :LPWIN32_FIND_DATA], :HANDLE =begin BOOL WINAPI CreateHardLink( __in LPCTSTR lpFileName, __in LPCTSTR lpExistingFileName, __reserved LPSECURITY_ATTRIBUTES lpSecurityAttributes ); =end safe_attach_function :CreateHardLinkW, [:LPCTSTR, :LPCTSTR, :LPSECURITY_ATTRIBUTES], :BOOLEAN =begin BOOLEAN WINAPI CreateSymbolicLink( __in LPTSTR lpSymlinkFileName, __in LPTSTR lpTargetFileName, __in DWORD dwFlags ); =end safe_attach_function :CreateSymbolicLinkW, [:LPTSTR, :LPTSTR, :DWORD], :BOOLEAN =begin DWORD WINAPI GetLongPathName( __in LPCTSTR lpszShortPath, __out LPTSTR lpszLongPath, __in DWORD cchBuffer ); =end safe_attach_function :GetLongPathNameW, [:LPCTSTR, :LPTSTR, :DWORD], :DWORD =begin DWORD WINAPI GetShortPathName( __in LPCTSTR lpszLongPath, __out LPTSTR lpszShortPath, __in DWORD cchBuffer ); =end safe_attach_function :GetShortPathNameW, [:LPCTSTR, :LPTSTR, :DWORD], :DWORD =begin BOOL WINAPI DeviceIoControl( __in HANDLE hDevice, __in DWORD dwIoControlCode, __in_opt LPVOID lpInBuffer, __in DWORD nInBufferSize, __out_opt LPVOID lpOutBuffer, __in DWORD nOutBufferSize, __out_opt LPDWORD lpBytesReturned, __inout_opt LPOVERLAPPED lpOverlapped ); =end safe_attach_function :DeviceIoControl, [:HANDLE, :DWORD, :LPVOID, :DWORD, :LPVOID, :DWORD, :LPDWORD, :pointer], :BOOL ############################################### # Helpers ############################################### # takes the given path pre-pends "\\?\" and # UTF-16LE encodes it. Used to prepare paths # to be passed to the *W vesion of WinAPI File # functions def encode_path(path) (path_prepender << path.gsub(::File::SEPARATOR, ::File::ALT_SEPARATOR)).to_wstring end def path_prepender "\\\\?\\" end # retrieves a file search handle and passes it # to +&block+ along with the find_data. also # ensures the handle is closed on exit of the block def file_search_handle(path, &block) begin # Workaround for CHEF-4419: # Make sure paths starting with "/" has a drive letter # assigned from the current working diretory. # Note: With CHEF-4427 this issue will be fixed with a # broader fix to map all the paths starting with "/" to # SYSTEM_DRIVE on windows. path = ::File.expand_path(path) if path.start_with? "/" path = encode_path(path) find_data = WIN32_FIND_DATA.new handle = FindFirstFileW(path, find_data) if handle == INVALID_HANDLE_VALUE Chef::ReservedNames::Win32::Error.raise! end block.call(handle, find_data) ensure FindClose(handle) if handle && handle != INVALID_HANDLE_VALUE end end # retrieves a file handle and passes it # to +&block+ along with the find_data. also # ensures the handle is closed on exit of the block def file_handle(path, &block) begin path = encode_path(path) handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, nil) if handle == INVALID_HANDLE_VALUE Chef::ReservedNames::Win32::Error.raise! end block.call(handle) ensure CloseHandle(handle) if handle && handle != INVALID_HANDLE_VALUE end end def symlink_file_handle(path, &block) begin path = encode_path(path) handle = CreateFileW(path, FILE_READ_EA, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, nil) if handle == INVALID_HANDLE_VALUE Chef::ReservedNames::Win32::Error.raise! end block.call(handle) ensure CloseHandle(handle) if handle && handle != INVALID_HANDLE_VALUE end end def retrieve_file_info(file_name) file_information = nil file_handle(file_name) do |handle| file_information = BY_HANDLE_FILE_INFORMATION.new success = GetFileInformationByHandle(handle, file_information) if success == 0 Chef::ReservedNames::Win32::Error.raise! end end file_information end end end end end chef-11.8.2/lib/chef/win32/api/unicode.rb0000644000004100000410000001313712254362222017706 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/api' class Chef module ReservedNames::Win32 module API module Unicode extend Chef::ReservedNames::Win32::API ############################################### # Win32 API Constants ############################################### CP_ACP = 0 CP_OEMCP = 1 CP_MACCP = 2 CP_THREAD_ACP = 3 CP_SYMBOL = 42 CP_UTF7 = 65000 CP_UTF8 = 65001 MB_PRECOMPOSED = 0x00000001 MB_COMPOSITE = 0x00000002 MB_USEGLYPHCHARS = 0x00000004 MB_ERR_INVALID_CHARS = 0x00000008 WC_COMPOSITECHECK = 0x00000200 WC_DISCARDNS = 0x00000010 WC_SEPCHARS = 0x00000020 WC_DEFAULTCHAR = 0x00000040 WC_NO_BEST_FIT_CHARS = 0x00000400 ANSI_CHARSET = 0 DEFAULT_CHARSET = 1 SYMBOL_CHARSET = 2 SHIFTJIS_CHARSET = 128 HANGEUL_CHARSET = 129 HANGUL_CHARSET = 129 GB2312_CHARSET = 134 CHINESEBIG5_CHARSET = 136 OEM_CHARSET = 255 JOHAB_CHARSET = 130 HEBREW_CHARSET = 177 ARABIC_CHARSET = 178 GREEK_CHARSET = 161 TURKISH_CHARSET = 162 VIETNAMESE_CHARSET = 163 THAI_CHARSET = 222 EASTEUROPE_CHARSET = 238 RUSSIAN_CHARSET = 204 IS_TEXT_UNICODE_ASCII16 = 0x0001 IS_TEXT_UNICODE_REVERSE_ASCII16 = 0x0010 IS_TEXT_UNICODE_STATISTICS = 0x0002 IS_TEXT_UNICODE_REVERSE_STATISTICS = 0x0020 IS_TEXT_UNICODE_CONTROLS = 0x0004 IS_TEXT_UNICODE_REVERSE_CONTROLS = 0x0040 IS_TEXT_UNICODE_SIGNATURE = 0x0008 IS_TEXT_UNICODE_REVERSE_SIGNATURE = 0x0080 IS_TEXT_UNICODE_ILLEGAL_CHARS = 0x0100 IS_TEXT_UNICODE_ODD_LENGTH = 0x0200 IS_TEXT_UNICODE_DBCS_LEADBYTE = 0x0400 IS_TEXT_UNICODE_NULL_BYTES = 0x1000 IS_TEXT_UNICODE_UNICODE_MASK = 0x000F IS_TEXT_UNICODE_REVERSE_MASK = 0x00F0 IS_TEXT_UNICODE_NOT_UNICODE_MASK = 0x0F00 IS_TEXT_UNICODE_NOT_ASCII_MASK = 0xF000 TCI_SRCCHARSET = 1 TCI_SRCCODEPAGE = 2 TCI_SRCFONTSIG = 3 TCI_SRCLOCALE = 0x100 ############################################### # Win32 API Bindings ############################################### ffi_lib 'kernel32', 'advapi32' =begin BOOL IsTextUnicode( __in const VOID *lpv, __in int iSize, __inout LPINT lpiResult ); =end safe_attach_function :IsTextUnicode, [:pointer, :int, :LPINT], :BOOL =begin int MultiByteToWideChar( __in UINT CodePage, __in DWORD dwFlags, __in LPCSTR lpMultiByteStr, __in int cbMultiByte, __out LPWSTR lpWideCharStr, __in int cchWideChar ); =end safe_attach_function :MultiByteToWideChar, [:UINT, :DWORD, :LPCSTR, :int, :LPWSTR, :int], :int =begin int WideCharToMultiByte( __in UINT CodePage, __in DWORD dwFlags, __in LPCWSTR lpWideCharStr, __in int cchWideChar, __out LPSTR lpMultiByteStr, __in int cbMultiByte, __in LPCSTR lpDefaultChar, __out LPBOOL lpUsedDefaultChar ); =end safe_attach_function :WideCharToMultiByte, [:UINT, :DWORD, :LPCWSTR, :int, :LPSTR, :int, :LPCSTR, :LPBOOL], :int ############################################### # Helpers ############################################### def utf8_to_wide(ustring) # ensure it is actually UTF-8 # Ruby likes to mark binary data as ASCII-8BIT ustring = (ustring + "").force_encoding('UTF-8') if ustring.respond_to?(:force_encoding) && ustring.encoding.name != "UTF-8" # ensure we have the double-null termination Windows Wide likes ustring = ustring + "\000\000" if ustring[-1].chr != "\000" # encode it all as UTF-16LE AKA Windows Wide Character AKA Windows Unicode ustring = begin if ustring.respond_to?(:encode) ustring.encode('UTF-16LE') else require 'iconv' Iconv.conv("UTF-16LE", "UTF-8", ustring) end end ustring end def wide_to_utf8(wstring) # ensure it is actually UTF-16LE # Ruby likes to mark binary data as ASCII-8BIT wstring = wstring.force_encoding('UTF-16LE') if wstring.respond_to?(:force_encoding) # encode it all as UTF-8 wstring = begin if wstring.respond_to?(:encode) wstring.encode('UTF-8') else require 'iconv' Iconv.conv("UTF-8", "UTF-16LE", wstring) end end # remove trailing CRLF and NULL characters wstring.strip! wstring end end end end end chef-11.8.2/lib/chef/win32/api/error.rb0000644000004100000410000012777412254362222017426 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/api' class Chef module ReservedNames::Win32 module API module Error extend Chef::ReservedNames::Win32::API ############################################### # Win32 API Constants ############################################### S_OK = 0 NO_ERROR = 0 ERROR_SUCCESS = 0 ERROR_INVALID_FUNCTION = 1 ERROR_FILE_NOT_FOUND = 2 ERROR_PATH_NOT_FOUND = 3 ERROR_TOO_MANY_OPEN_FILES = 4 ERROR_ACCESS_DENIED = 5 ERROR_INVALID_HANDLE = 6 ERROR_ARENA_TRASHED = 7 ERROR_NOT_ENOUGH_MEMORY = 8 ERROR_INVALID_BLOCK = 9 ERROR_BAD_ENVIRONMENT = 10 ERROR_BAD_FORMAT = 11 ERROR_INVALID_ACCESS = 12 ERROR_INVALID_DATA = 13 ERROR_INVALID_DRIVE = 15 ERROR_CURRENT_DIRECTORY = 16 ERROR_NOT_SAME_DEVICE = 17 ERROR_NO_MORE_FILES = 18 ERROR_WRITE_PROTECT = 19 ERROR_BAD_UNIT = 20 ERROR_NOT_READY = 21 ERROR_BAD_COMMAND = 22 ERROR_CRC = 23 ERROR_BAD_LENGTH = 24 ERROR_SEEK = 25 ERROR_NOT_DOS_DISK = 26 ERROR_SECTOR_NOT_FOUND = 27 ERROR_OUT_OF_PAPER = 28 ERROR_WRITE_FAULT = 29 ERROR_READ_FAULT = 30 ERROR_GEN_FAILURE = 31 ERROR_SHARING_VIOLATION = 32 ERROR_LOCK_VIOLATION = 33 ERROR_WRONG_DISK = 34 ERROR_FCB_UNAVAILABLE = 35 # gets returned for some unsuccessful DeviceIoControl calls ERROR_SHARING_BUFFER_EXCEEDED = 36 ERROR_HANDLE_EOF = 38 ERROR_HANDLE_DISK_FULL = 39 ERROR_NOT_SUPPORTED = 50 ERROR_REM_NOT_LIST = 51 ERROR_DUP_NAME = 52 ERROR_BAD_NETPATH = 53 ERROR_NETWORK_BUSY = 54 ERROR_DEV_NOT_EXIST = 55 ERROR_TOO_MANY_CMDS = 56 ERROR_ADAP_HDW_ERR = 57 ERROR_BAD_NET_RESP = 58 ERROR_UNEXP_NET_ERR = 59 ERROR_BAD_REM_ADAP = 60 ERROR_PRINTQ_FULL = 61 ERROR_NO_SPOOL_SPACE = 62 ERROR_PRINT_CANCELLED = 63 ERROR_NETNAME_DELETED = 64 ERROR_NETWORK_ACCESS_DENIED = 65 ERROR_BAD_DEV_TYPE = 66 ERROR_BAD_NET_NAME = 67 ERROR_TOO_MANY_NAMES = 68 ERROR_TOO_MANY_SESS = 69 ERROR_SHARING_PAUSED = 70 ERROR_REQ_NOT_ACCEP = 71 ERROR_REDIR_PAUSED = 72 ERROR_FILE_EXISTS = 80 ERROR_DUP_FCB = 81 ERROR_CANNOT_MAKE = 82 ERROR_FAIL_I24 = 83 ERROR_OUT_OF_STRUCTURES = 84 ERROR_ALREADY_ASSIGNED = 85 ERROR_INVALID_PASSWORD = 86 ERROR_INVALID_PARAMETER = 87 ERROR_NET_WRITE_FAULT = 88 ERROR_NO_PROC_SLOTS = 89 # no process slots available ERROR_NOT_FROZEN = 90 ERR_TSTOVFL = 91 # timer service table overflow ERR_TSTDUP = 92 # timer service table duplicate ERROR_NO_ITEMS = 93 # There were no items to operate upon ERROR_INTERRUPT = 95 # interrupted system call ERROR_TOO_MANY_SEMAPHORES = 100 ERROR_EXCL_SEM_ALREADY_OWNED = 101 ERROR_SEM_IS_SET = 102 ERROR_TOO_MANY_SEM_REQUESTS = 103 ERROR_INVALID_AT_INTERRUPT_TIME = 104 ERROR_SEM_OWNER_DIED = 105 # waitsem found owner died ERROR_SEM_USER_LIMIT = 106 # too many procs have this sem ERROR_DISK_CHANGE = 107 # insert disk b into drive a ERROR_DRIVE_LOCKED = 108 # drive locked by another process ERROR_BROKEN_PIPE = 109 # write on pipe with no reader ERROR_OPEN_FAILED = 110 # open/created failed ERROR_DISK_FULL = 112 # not enough space ERROR_NO_MORE_SEARCH_HANDLES = 113 # can't allocate ERROR_INVALID_TARGET_HANDLE = 114 # handle in DOSDUPHANDLE is invalid ERROR_PROTECTION_VIOLATION = 115 # bad user virtual address ERROR_VIOKBD_REQUEST = 116 ERROR_INVALID_CATEGORY = 117 # category for DEVIOCTL not defined ERROR_INVALID_VERIFY_SWITCH = 118 # invalid value ERROR_BAD_DRIVER_LEVEL = 119 # DosDevIOCTL not level four ERROR_CALL_NOT_IMPLEMENTED = 120 ERROR_SEM_TIMEOUT = 121 # timeout from semaphore function ERROR_INSUFFICIENT_BUFFER = 122 ERROR_INVALID_NAME = 123 # illegal char or malformed file system name ERROR_INVALID_LEVEL = 124 # unimplemented level for info retrieval ERROR_NO_VOLUME_LABEL = 125 # no volume label found ERROR_MOD_NOT_FOUND = 126 # w_getprocaddr, w_getmodhandle ERROR_PROC_NOT_FOUND = 127 # w_getprocaddr ERROR_WAIT_NO_CHILDREN = 128 # CWait finds to children ERROR_CHILD_NOT_COMPLETE = 129 # CWait children not dead yet ERROR_DIRECT_ACCESS_HANDLE = 130 # invalid for direct disk access ERROR_NEGATIVE_SEEK = 131 # tried to seek negative offset ERROR_SEEK_ON_DEVICE = 132 # tried to seek on device or pipe ERROR_IS_JOIN_TARGET = 133 ERROR_IS_JOINED = 134 ERROR_IS_SUBSTED = 135 ERROR_NOT_JOINED = 136 ERROR_NOT_SUBSTED = 137 ERROR_JOIN_TO_JOIN = 138 ERROR_SUBST_TO_SUBST = 139 ERROR_JOIN_TO_SUBST = 140 ERROR_SUBST_TO_JOIN = 141 ERROR_BUSY_DRIVE = 142 ERROR_SAME_DRIVE = 143 ERROR_DIR_NOT_ROOT = 144 ERROR_DIR_NOT_EMPTY = 145 ERROR_IS_SUBST_PATH = 146 ERROR_IS_JOIN_PATH = 147 ERROR_PATH_BUSY = 148 ERROR_IS_SUBST_TARGET = 149 ERROR_SYSTEM_TRACE = 150 # system trace error ERROR_INVALID_EVENT_COUNT = 151 # DosMuxSemWait errors ERROR_TOO_MANY_MUXWAITERS = 152 ERROR_INVALID_LIST_FORMAT = 153 ERROR_LABEL_TOO_LONG = 154 ERROR_TOO_MANY_TCBS = 155 ERROR_SIGNAL_REFUSED = 156 ERROR_DISCARDED = 157 ERROR_NOT_LOCKED = 158 ERROR_BAD_THREADID_ADDR = 159 ERROR_BAD_ARGUMENTS = 160 ERROR_BAD_PATHNAME = 161 ERROR_SIGNAL_PENDING = 162 ERROR_UNCERTAIN_MEDIA = 163 ERROR_MAX_THRDS_REACHED = 164 ERROR_MONITORS_NOT_SUPPORTED = 165 ERROR_LOCK_FAILED = 167 ERROR_BUSY = 170 ERROR_CANCEL_VIOLATION = 173 ERROR_ATOMIC_LOCKS_NOT_SUPPORTED= 174 ERROR_INVALID_SEGMENT_NUMBER = 180 ERROR_INVALID_CALLGATE = 181 ERROR_INVALID_ORDINAL = 182 ERROR_ALREADY_EXISTS = 183 ERROR_NO_CHILD_PROCESS = 184 ERROR_CHILD_ALIVE_NOWAIT = 185 ERROR_INVALID_FLAG_NUMBER = 186 ERROR_SEM_NOT_FOUND = 187 ERROR_INVALID_STARTING_CODESEG = 188 ERROR_INVALID_STACKSEG = 189 ERROR_INVALID_MODULETYPE = 190 ERROR_INVALID_EXE_SIGNATURE = 191 ERROR_EXE_MARKED_INVALID = 192 ERROR_BAD_EXE_FORMAT = 193 ERROR_ITERATED_DATA_EXCEEDS_64k = 194 ERROR_INVALID_MINALLOCSIZE = 195 ERROR_DYNLINK_FROM_INVALID_RING = 196 ERROR_IOPL_NOT_ENABLED = 197 ERROR_INVALID_SEGDPL = 198 ERROR_AUTODATASEG_EXCEEDS_64k = 199 ERROR_RING2SEG_MUST_BE_MOVABLE = 200 ERROR_RELOC_CHAIN_XEEDS_SEGLIM = 201 ERROR_INFLOOP_IN_RELOC_CHAIN = 202 ERROR_ENVVAR_NOT_FOUND = 203 ERROR_NOT_CURRENT_CTRY = 204 ERROR_NO_SIGNAL_SENT = 205 ERROR_FILENAME_EXCED_RANGE = 206 # if filename > 8.3 ERROR_RING2_STACK_IN_USE = 207 # for FAPI ERROR_META_EXPANSION_TOO_LONG = 208 # if "*a" > 8.3 ERROR_INVALID_SIGNAL_NUMBER = 209 ERROR_THREAD_1_INACTIVE = 210 ERROR_INFO_NOT_AVAIL = 211 #@@ PTM 5550 ERROR_LOCKED = 212 ERROR_BAD_DYNALINK = 213 #@@ PTM 5760 ERROR_TOO_MANY_MODULES = 214 ERROR_NESTING_NOT_ALLOWED = 215 ERROR_EXE_MACHINE_TYPE_MISMATCH = 216 ERROR_BAD_PIPE = 230 ERROR_PIPE_BUSY = 231 ERROR_NO_DATA = 232 ERROR_PIPE_NOT_CONNECTED = 233 ERROR_MORE_DATA = 234 ERROR_VC_DISCONNECTED = 240 ERROR_INVALID_EA_NAME = 254 ERROR_EA_LIST_INCONSISTENT = 255 ERROR_NO_MORE_ITEMS = 259 ERROR_CANNOT_COPY = 266 ERROR_DIRECTORY = 267 ERROR_EAS_DIDNT_FIT = 275 ERROR_EA_FILE_CORRUPT = 276 ERROR_EA_TABLE_FULL = 277 ERROR_INVALID_EA_HANDLE = 278 ERROR_EAS_NOT_SUPPORTED = 282 ERROR_NOT_OWNER = 288 ERROR_TOO_MANY_POSTS = 298 ERROR_PARTIAL_COPY = 299 ERROR_OPLOCK_NOT_GRANTED = 300 ERROR_INVALID_OPLOCK_PROTOCOL = 301 ERROR_DISK_TOO_FRAGMENTED = 302 ERROR_MR_MID_NOT_FOUND = 317 ERROR_SCOPE_NOT_FOUND = 318 ERROR_FAIL_NOACTION_REBOOT = 350 ERROR_FAIL_SHUTDOWN = 351 ERROR_FAIL_RESTART = 352 ERROR_MAX_SESSIONS_REACHED = 353 ERROR_INVALID_ADDRESS = 487 ERROR_USER_PROFILE_LOAD = 500 ERROR_ARITHMETIC_OVERFLOW = 534 ERROR_PIPE_CONNECTED = 535 ERROR_PIPE_LISTENING = 536 ERROR_EA_ACCESS_DENIED = 994 ERROR_OPERATION_ABORTED = 995 ERROR_IO_INCOMPLETE = 996 ERROR_IO_PENDING = 997 ERROR_NOACCESS = 998 ERROR_SWAPERROR = 999 ERROR_STACK_OVERFLOW = 1001 ERROR_INVALID_MESSAGE = 1002 ERROR_CAN_NOT_COMPLETE = 1003 ERROR_INVALID_FLAGS = 1004 ERROR_UNRECOGNIZED_VOLUME = 1005 ERROR_FILE_INVALID = 1006 ERROR_FULLSCREEN_MODE = 1007 ERROR_NO_TOKEN = 1008 ERROR_BADDB = 1009 ERROR_BADKEY = 1010 ERROR_CANTOPEN = 1011 ERROR_CANTREAD = 1012 ERROR_CANTWRITE = 1013 ERROR_REGISTRY_RECOVERED = 1014 ERROR_REGISTRY_CORRUPT = 1015 ERROR_REGISTRY_IO_FAILED = 1016 ERROR_NOT_REGISTRY_FILE = 1017 ERROR_KEY_DELETED = 1018 ERROR_NO_LOG_SPACE = 1019 ERROR_KEY_HAS_CHILDREN = 1020 ERROR_CHILD_MUST_BE_VOLATILE = 1021 ERROR_NOTIFY_ENUM_DIR = 1022 ERROR_DEPENDENT_SERVICES_RUNNING = 1051 ERROR_INVALID_SERVICE_CONTROL = 1052 ERROR_SERVICE_REQUEST_TIMEOUT = 1053 ERROR_SERVICE_NO_THREAD = 1054 ERROR_SERVICE_DATABASE_LOCKED = 1055 ERROR_SERVICE_ALREADY_RUNNING = 1056 ERROR_INVALID_SERVICE_ACCOUNT = 1057 ERROR_SERVICE_DISABLED = 1058 ERROR_CIRCULAR_DEPENDENCY = 1059 ERROR_SERVICE_DOES_NOT_EXIST = 1060 ERROR_SERVICE_CANNOT_ACCEPT_CTRL = 1061 ERROR_SERVICE_NOT_ACTIVE = 1062 ERROR_FAILED_SERVICE_CONTROLLER_CONNECT = 1063 ERROR_EXCEPTION_IN_SERVICE = 1064 ERROR_DATABASE_DOES_NOT_EXIST = 1065 ERROR_SERVICE_SPECIFIC_ERROR = 1066 ERROR_PROCESS_ABORTED = 1067 ERROR_SERVICE_DEPENDENCY_FAIL = 1068 ERROR_SERVICE_LOGON_FAILED = 1069 ERROR_SERVICE_START_HANG = 1070 ERROR_INVALID_SERVICE_LOCK = 1071 ERROR_SERVICE_MARKED_FOR_DELETE = 1072 ERROR_SERVICE_EXISTS = 1073 ERROR_ALREADY_RUNNING_LKG = 1074 ERROR_SERVICE_DEPENDENCY_DELETED = 1075 ERROR_BOOT_ALREADY_ACCEPTED = 1076 ERROR_SERVICE_NEVER_STARTED = 1077 ERROR_DUPLICATE_SERVICE_NAME = 1078 ERROR_DIFFERENT_SERVICE_ACCOUNT = 1079 ERROR_CANNOT_DETECT_DRIVER_FAILURE = 1080 ERROR_CANNOT_DETECT_PROCESS_ABORT = 1081 ERROR_NO_RECOVERY_PROGRAM = 1082 ERROR_SERVICE_NOT_IN_EXE = 1083 ERROR_END_OF_MEDIA = 1100 ERROR_FILEMARK_DETECTED = 1101 ERROR_BEGINNING_OF_MEDIA = 1102 ERROR_SETMARK_DETECTED = 1103 ERROR_NO_DATA_DETECTED = 1104 ERROR_PARTITION_FAILURE = 1105 ERROR_INVALID_BLOCK_LENGTH = 1106 ERROR_DEVICE_NOT_PARTITIONED = 1107 ERROR_UNABLE_TO_LOCK_MEDIA = 1108 ERROR_UNABLE_TO_UNLOAD_MEDIA = 1109 ERROR_MEDIA_CHANGED = 1110 ERROR_BUS_RESET = 1111 ERROR_NO_MEDIA_IN_DRIVE = 1112 ERROR_NO_UNICODE_TRANSLATION = 1113 ERROR_DLL_INIT_FAILED = 1114 ERROR_SHUTDOWN_IN_PROGRESS = 1115 ERROR_NO_SHUTDOWN_IN_PROGRESS = 1116 ERROR_IO_DEVICE = 1117 ERROR_SERIAL_NO_DEVICE = 1118 ERROR_IRQ_BUSY = 1119 ERROR_MORE_WRITES = 1120 ERROR_COUNTER_TIMEOUT = 1121 ERROR_FLOPPY_ID_MARK_NOT_FOUND = 1122 ERROR_FLOPPY_WRONG_CYLINDER = 1123 ERROR_FLOPPY_UNKNOWN_ERROR = 1124 ERROR_FLOPPY_BAD_REGISTERS = 1125 ERROR_DISK_RECALIBRATE_FAILED = 1126 ERROR_DISK_OPERATION_FAILED = 1127 ERROR_DISK_RESET_FAILED = 1128 ERROR_EOM_OVERFLOW = 1129 ERROR_NOT_ENOUGH_SERVER_MEMORY = 1130 ERROR_POSSIBLE_DEADLOCK = 1131 ERROR_MAPPED_ALIGNMENT = 1132 ERROR_SET_POWER_STATE_VETOED = 1140 ERROR_SET_POWER_STATE_FAILED = 1141 ERROR_TOO_MANY_LINKS = 1142 ERROR_OLD_WIN_VERSION = 1150 ERROR_APP_WRONG_OS = 1151 ERROR_SINGLE_INSTANCE_APP = 1152 ERROR_RMODE_APP = 1153 ERROR_INVALID_DLL = 1154 ERROR_NO_ASSOCIATION = 1155 ERROR_DDE_FAIL = 1156 ERROR_DLL_NOT_FOUND = 1157 ERROR_NO_MORE_USER_HANDLES = 1158 ERROR_MESSAGE_SYNC_ONLY = 1159 ERROR_SOURCE_ELEMENT_EMPTY = 1160 ERROR_DESTINATION_ELEMENT_FULL = 1161 ERROR_ILLEGAL_ELEMENT_ADDRESS = 1162 ERROR_MAGAZINE_NOT_PRESENT = 1163 ERROR_DEVICE_REINITIALIZATION_NEEDED = 1164 ERROR_DEVICE_REQUIRES_CLEANING = 1165 ERROR_DEVICE_DOOR_OPEN = 1166 ERROR_DEVICE_NOT_CONNECTED = 1167 ERROR_NOT_FOUND = 1168 ERROR_NO_MATCH = 1169 ERROR_SET_NOT_FOUND = 1170 ERROR_POINT_NOT_FOUND = 1171 ERROR_NO_TRACKING_SERVICE = 1172 ERROR_NO_VOLUME_ID = 1173 ERROR_UNABLE_TO_REMOVE_REPLACED = 1175 ERROR_UNABLE_TO_MOVE_REPLACEMENT = 1176 ERROR_UNABLE_TO_MOVE_REPLACEMENT_2 = 1177 ERROR_JOURNAL_DELETE_IN_PROGRESS = 1178 ERROR_JOURNAL_NOT_ACTIVE = 1179 ERROR_POTENTIAL_FILE_FOUND = 1180 ERROR_JOURNAL_ENTRY_DELETED = 1181 ERROR_BAD_DEVICE = 1200 ERROR_CONNECTION_UNAVAIL = 1201 ERROR_DEVICE_ALREADY_REMEMBERED = 1202 ERROR_NO_NET_OR_BAD_PATH = 1203 ERROR_BAD_PROVIDER = 1204 ERROR_CANNOT_OPEN_PROFILE = 1205 ERROR_BAD_PROFILE = 1206 ERROR_NOT_CONTAINER = 1207 ERROR_EXTENDED_ERROR = 1208 ERROR_INVALID_GROUPNAME = 1209 ERROR_INVALID_COMPUTERNAME = 1210 ERROR_INVALID_EVENTNAME = 1211 ERROR_INVALID_DOMAINNAME = 1212 ERROR_INVALID_SERVICENAME = 1213 ERROR_INVALID_NETNAME = 1214 ERROR_INVALID_SHARENAME = 1215 ERROR_INVALID_PASSWORDNAME = 1216 ERROR_INVALID_MESSAGENAME = 1217 ERROR_INVALID_MESSAGEDEST = 1218 ERROR_SESSION_CREDENTIAL_CONFLICT = 1219 ERROR_REMOTE_SESSION_LIMIT_EXCEEDED = 1220 ERROR_DUP_DOMAINNAME = 1221 ERROR_NO_NETWORK = 1222 ERROR_CANCELLED = 1223 ERROR_USER_MAPPED_FILE = 1224 ERROR_CONNECTION_REFUSED = 1225 ERROR_GRACEFUL_DISCONNECT = 1226 ERROR_ADDRESS_ALREADY_ASSOCIATED = 1227 ERROR_ADDRESS_NOT_ASSOCIATED = 1228 ERROR_CONNECTION_INVALID = 1229 ERROR_CONNECTION_ACTIVE = 1230 ERROR_NETWORK_UNREACHABLE = 1231 ERROR_HOST_UNREACHABLE = 1232 ERROR_PROTOCOL_UNREACHABLE = 1233 ERROR_PORT_UNREACHABLE = 1234 ERROR_REQUEST_ABORTED = 1235 ERROR_CONNECTION_ABORTED = 1236 ERROR_RETRY = 1237 ERROR_CONNECTION_COUNT_LIMIT = 1238 ERROR_LOGIN_TIME_RESTRICTION = 1239 ERROR_LOGIN_WKSTA_RESTRICTION = 1240 ERROR_INCORRECT_ADDRESS = 1241 ERROR_ALREADY_REGISTERED = 1242 ERROR_SERVICE_NOT_FOUND = 1243 ERROR_NOT_AUTHENTICATED = 1244 ERROR_NOT_LOGGED_ON = 1245 ERROR_CONTINUE = 1246 ERROR_ALREADY_INITIALIZED = 1247 ERROR_NO_MORE_DEVICES = 1248 ERROR_NO_SUCH_SITE = 1249 ERROR_DOMAIN_CONTROLLER_EXISTS = 1250 ERROR_ONLY_IF_CONNECTED = 1251 ERROR_OVERRIDE_NOCHANGES = 1252 ERROR_BAD_USER_PROFILE = 1253 ERROR_NOT_SUPPORTED_ON_SBS = 1254 ERROR_SERVER_SHUTDOWN_IN_PROGRESS = 1255 ERROR_HOST_DOWN = 1256 ERROR_ACCESS_DISABLED_BY_POLICY = 1260 ERROR_REG_NAT_CONSUMPTION = 1261 ERROR_PKINIT_FAILURE = 1263 ERROR_SMARTCARD_SUBSYSTEM_FAILURE = 1264 ERROR_DOWNGRADE_DETECTED = 1265 ERROR_MACHINE_LOCKED = 1271 ERROR_CALLBACK_SUPPLIED_INVALID_DATA = 1273 ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED= 1274 ERROR_DRIVER_BLOCKED = 1275 ERROR_INVALID_IMPORT_OF_NON_DLL = 1276 ERROR_NOT_ALL_ASSIGNED = 1300 ERROR_SOME_NOT_MAPPED = 1301 ERROR_NO_QUOTAS_FOR_ACCOUNT = 1302 ERROR_LOCAL_USER_SESSION_KEY = 1303 ERROR_NULL_LM_PASSWORD = 1304 ERROR_UNKNOWN_REVISION = 1305 ERROR_REVISION_MISMATCH = 1306 ERROR_INVALID_OWNER = 1307 ERROR_INVALID_PRIMARY_GROUP = 1308 ERROR_NO_IMPERSONATION_TOKEN = 1309 ERROR_CANT_DISABLE_MANDATORY = 1310 ERROR_NO_LOGON_SERVERS = 1311 ERROR_NO_SUCH_LOGON_SESSION = 1312 ERROR_NO_SUCH_PRIVILEGE = 1313 ERROR_PRIVILEGE_NOT_HELD = 1314 ERROR_INVALID_ACCOUNT_NAME = 1315 ERROR_USER_EXISTS = 1316 ERROR_NO_SUCH_USER = 1317 ERROR_GROUP_EXISTS = 1318 ERROR_NO_SUCH_GROUP = 1319 ERROR_MEMBER_IN_GROUP = 1320 ERROR_MEMBER_NOT_IN_GROUP = 1321 ERROR_LAST_ADMIN = 1322 ERROR_WRONG_PASSWORD = 1323 ERROR_ILL_FORMED_PASSWORD = 1324 ERROR_PASSWORD_RESTRICTION = 1325 ERROR_LOGON_FAILURE = 1326 ERROR_ACCOUNT_RESTRICTION = 1327 ERROR_INVALID_LOGON_HOURS = 1328 ERROR_INVALID_WORKSTATION = 1329 ERROR_PASSWORD_EXPIRED = 1330 ERROR_ACCOUNT_DISABLED = 1331 ERROR_NONE_MAPPED = 1332 ERROR_TOO_MANY_LUIDS_REQUESTED = 1333 ERROR_LUIDS_EXHAUSTED = 1334 ERROR_INVALID_SUB_AUTHORITY = 1335 ERROR_INVALID_ACL = 1336 ERROR_INVALID_SID = 1337 ERROR_INVALID_SECURITY_DESCR = 1338 ERROR_BAD_INHERITANCE_ACL = 1340 ERROR_SERVER_DISABLED = 1341 ERROR_SERVER_NOT_DISABLED = 1342 ERROR_INVALID_ID_AUTHORITY = 1343 ERROR_ALLOTTED_SPACE_EXCEEDED = 1344 ERROR_INVALID_GROUP_ATTRIBUTES = 1345 ERROR_BAD_IMPERSONATION_LEVEL = 1346 ERROR_CANT_OPEN_ANONYMOUS = 1347 ERROR_BAD_VALIDATION_CLASS = 1348 ERROR_BAD_TOKEN_TYPE = 1349 ERROR_NO_SECURITY_ON_OBJECT = 1350 ERROR_CANT_ACCESS_DOMAIN_INFO = 1351 ERROR_INVALID_SERVER_STATE = 1352 ERROR_INVALID_DOMAIN_STATE = 1353 ERROR_INVALID_DOMAIN_ROLE = 1354 ERROR_NO_SUCH_DOMAIN = 1355 ERROR_DOMAIN_EXISTS = 1356 ERROR_DOMAIN_LIMIT_EXCEEDED = 1357 ERROR_INTERNAL_DB_CORRUPTION = 1358 ERROR_INTERNAL_ERROR = 1359 ERROR_GENERIC_NOT_MAPPED = 1360 ERROR_BAD_DESCRIPTOR_FORMAT = 1361 ERROR_NOT_LOGON_PROCESS = 1362 ERROR_LOGON_SESSION_EXISTS = 1363 ERROR_NO_SUCH_PACKAGE = 1364 ERROR_BAD_LOGON_SESSION_STATE = 1365 ERROR_LOGON_SESSION_COLLISION = 1366 ERROR_INVALID_LOGON_TYPE = 1367 ERROR_CANNOT_IMPERSONATE = 1368 ERROR_RXACT_INVALID_STATE = 1369 ERROR_RXACT_COMMIT_FAILURE = 1370 ERROR_SPECIAL_ACCOUNT = 1371 ERROR_SPECIAL_GROUP = 1372 ERROR_SPECIAL_USER = 1373 ERROR_MEMBERS_PRIMARY_GROUP = 1374 ERROR_TOKEN_ALREADY_IN_USE = 1375 ERROR_NO_SUCH_ALIAS = 1376 ERROR_MEMBER_NOT_IN_ALIAS = 1377 ERROR_MEMBER_IN_ALIAS = 1378 ERROR_ALIAS_EXISTS = 1379 ERROR_LOGON_NOT_GRANTED = 1380 ERROR_TOO_MANY_SECRETS = 1381 ERROR_SECRET_TOO_LONG = 1382 ERROR_INTERNAL_DB_ERROR = 1383 ERROR_TOO_MANY_CONTEXT_IDS = 1384 ERROR_LOGON_TYPE_NOT_GRANTED = 1385 ERROR_NT_CROSS_ENCRYPTION_REQUIRED = 1386 ERROR_NO_SUCH_MEMBER = 1387 ERROR_INVALID_MEMBER = 1388 ERROR_TOO_MANY_SIDS = 1389 ERROR_LM_CROSS_ENCRYPTION_REQUIRED = 1390 ERROR_NO_INHERITANCE = 1391 ERROR_FILE_CORRUPT = 1392 ERROR_DISK_CORRUPT = 1393 ERROR_NO_USER_SESSION_KEY = 1394 ERROR_LICENSE_QUOTA_EXCEEDED = 1395 ERROR_WRONG_TARGET_NAME = 1396 ERROR_MUTUAL_AUTH_FAILED = 1397 ERROR_TIME_SKEW = 1398 ERROR_CURRENT_DOMAIN_NOT_ALLOWED = 1399 ERROR_INVALID_WINDOW_HANDLE = 1400 ERROR_INVALID_MENU_HANDLE = 1401 ERROR_INVALID_CURSOR_HANDLE = 1402 ERROR_INVALID_ACCEL_HANDLE = 1403 ERROR_INVALID_HOOK_HANDLE = 1404 ERROR_INVALID_DWP_HANDLE = 1405 ERROR_TLW_WITH_WSCHILD = 1406 ERROR_CANNOT_FIND_WND_CLASS = 1407 ERROR_WINDOW_OF_OTHER_THREAD = 1408 ERROR_HOTKEY_ALREADY_REGISTERED = 1409 ERROR_CLASS_ALREADY_EXISTS = 1410 ERROR_CLASS_DOES_NOT_EXIST = 1411 ERROR_CLASS_HAS_WINDOWS = 1412 ERROR_INVALID_INDEX = 1413 ERROR_INVALID_ICON_HANDLE = 1414 ERROR_PRIVATE_DIALOG_INDEX = 1415 ERROR_LISTBOX_ID_NOT_FOUND = 1416 ERROR_NO_WILDCARD_CHARACTERS = 1417 ERROR_CLIPBOARD_NOT_OPEN = 1418 ERROR_HOTKEY_NOT_REGISTERED = 1419 ERROR_WINDOW_NOT_DIALOG = 1420 ERROR_CONTROL_ID_NOT_FOUND = 1421 ERROR_INVALID_COMBOBOX_MESSAGE = 1422 ERROR_WINDOW_NOT_COMBOBOX = 1423 ERROR_INVALID_EDIT_HEIGHT = 1424 ERROR_DC_NOT_FOUND = 1425 ERROR_INVALID_HOOK_FILTER = 1426 ERROR_INVALID_FILTER_PROC = 1427 ERROR_HOOK_NEEDS_HMOD = 1428 ERROR_GLOBAL_ONLY_HOOK = 1429 ERROR_JOURNAL_HOOK_SET = 1430 ERROR_HOOK_NOT_INSTALLED = 1431 ERROR_INVALID_LB_MESSAGE = 1432 ERROR_SETCOUNT_ON_BAD_LB = 1433 ERROR_LB_WITHOUT_TABSTOPS = 1434 ERROR_DESTROY_OBJECT_OF_OTHER_THREAD = 1435 ERROR_CHILD_WINDOW_MENU = 1436 ERROR_NO_SYSTEM_MENU = 1437 ERROR_INVALID_MSGBOX_STYLE = 1438 ERROR_INVALID_SPI_VALUE = 1439 ERROR_SCREEN_ALREADY_LOCKED = 1440 ERROR_HWNDS_HAVE_DIFF_PARENT = 1441 ERROR_NOT_CHILD_WINDOW = 1442 ERROR_INVALID_GW_COMMAND = 1443 ERROR_INVALID_THREAD_ID = 1444 ERROR_NON_MDICHILD_WINDOW = 1445 ERROR_POPUP_ALREADY_ACTIVE = 1446 ERROR_NO_SCROLLBARS = 1447 ERROR_INVALID_SCROLLBAR_RANGE = 1448 ERROR_INVALID_SHOWWIN_COMMAND = 1449 ERROR_NO_SYSTEM_RESOURCES = 1450 ERROR_NONPAGED_SYSTEM_RESOURCES = 1451 ERROR_PAGED_SYSTEM_RESOURCES = 1452 ERROR_WORKING_SET_QUOTA = 1453 ERROR_PAGEFILE_QUOTA = 1454 ERROR_COMMITMENT_LIMIT = 1455 ERROR_MENU_ITEM_NOT_FOUND = 1456 ERROR_INVALID_KEYBOARD_HANDLE = 1457 ERROR_HOOK_TYPE_NOT_ALLOWED = 1458 ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION = 1459 ERROR_TIMEOUT = 1460 ERROR_INVALID_MONITOR_HANDLE = 1461 ERROR_EVENTLOG_FILE_CORRUPT = 1500 ERROR_EVENTLOG_CANT_START = 1501 ERROR_LOG_FILE_FULL = 1502 ERROR_EVENTLOG_FILE_CHANGED = 1503 ERROR_INVALID_TASK_NAME = 1550 ERROR_INVALID_TASK_INDEX = 1551 ERROR_THREAD_ALREADY_IN_TASK = 1552 ERROR_INSTALL_SERVICE_FAILURE = 1601 ERROR_INSTALL_USEREXIT = 1602 ERROR_INSTALL_FAILURE = 1603 ERROR_INSTALL_SUSPEND = 1604 ERROR_UNKNOWN_PRODUCT = 1605 ERROR_UNKNOWN_FEATURE = 1606 ERROR_UNKNOWN_COMPONENT = 1607 ERROR_UNKNOWN_PROPERTY = 1608 ERROR_INVALID_HANDLE_STATE = 1609 ERROR_BAD_CONFIGURATION = 1610 ERROR_INDEX_ABSENT = 1611 ERROR_INSTALL_SOURCE_ABSENT = 1612 ERROR_INSTALL_PACKAGE_VERSION = 1613 ERROR_PRODUCT_UNINSTALLED = 1614 ERROR_BAD_QUERY_SYNTAX = 1615 ERROR_INVALID_FIELD = 1616 ERROR_DEVICE_REMOVED = 1617 ERROR_INSTALL_ALREADY_RUNNING = 1618 ERROR_INSTALL_PACKAGE_OPEN_FAILED = 1619 ERROR_INSTALL_PACKAGE_INVALID = 1620 ERROR_INSTALL_UI_FAILURE = 1621 ERROR_INSTALL_LOG_FAILURE = 1622 ERROR_INSTALL_LANGUAGE_UNSUPPORTED = 1623 ERROR_INSTALL_TRANSFORM_FAILURE = 1624 ERROR_INSTALL_PACKAGE_REJECTED = 1625 ERROR_FUNCTION_NOT_CALLED = 1626 ERROR_FUNCTION_FAILED = 1627 ERROR_INVALID_TABLE = 1628 ERROR_DATATYPE_MISMATCH = 1629 ERROR_UNSUPPORTED_TYPE = 1630 ERROR_CREATE_FAILED = 1631 ERROR_INSTALL_TEMP_UNWRITABLE = 1632 ERROR_INSTALL_PLATFORM_UNSUPPORTED = 1633 ERROR_INSTALL_NOTUSED = 1634 ERROR_PATCH_PACKAGE_OPEN_FAILED = 1635 ERROR_PATCH_PACKAGE_INVALID = 1636 ERROR_PATCH_PACKAGE_UNSUPPORTED = 1637 ERROR_PRODUCT_VERSION = 1638 ERROR_INVALID_COMMAND_LINE = 1639 ERROR_INSTALL_REMOTE_DISALLOWED = 1640 ERROR_SUCCESS_REBOOT_INITIATED = 1641 ERROR_UNKNOWN_PATCH = 1647 RPC_S_INVALID_STRING_BINDING = 1700 RPC_S_WRONG_KIND_OF_BINDING = 1701 RPC_S_INVALID_BINDING = 1702 RPC_S_PROTSEQ_NOT_SUPPORTED = 1703 RPC_S_INVALID_RPC_PROTSEQ = 1704 RPC_S_INVALID_STRING_UUID = 1705 RPC_S_INVALID_ENDPOINT_FORMAT = 1706 RPC_S_INVALID_NET_ADDR = 1707 RPC_S_NO_ENDPOINT_FOUND = 1708 RPC_S_INVALID_TIMEOUT = 1709 RPC_S_OBJECT_NOT_FOUND = 1710 RPC_S_ALREADY_REGISTERED = 1711 RPC_S_TYPE_ALREADY_REGISTERED = 1712 RPC_S_ALREADY_LISTENING = 1713 RPC_S_NO_PROTSEQS_REGISTERED = 1714 RPC_S_NOT_LISTENING = 1715 RPC_S_UNKNOWN_MGR_TYPE = 1716 RPC_S_UNKNOWN_IF = 1717 RPC_S_NO_BINDINGS = 1718 RPC_S_NO_PROTSEQS = 1719 RPC_S_CANT_CREATE_ENDPOINT = 1720 RPC_S_OUT_OF_RESOURCES = 1721 RPC_S_SERVER_UNAVAILABLE = 1722 RPC_S_SERVER_TOO_BUSY = 1723 RPC_S_INVALID_NETWORK_OPTIONS = 1724 RPC_S_NO_CALL_ACTIVE = 1725 RPC_S_CALL_FAILED = 1726 RPC_S_CALL_FAILED_DNE = 1727 RPC_S_PROTOCOL_ERROR = 1728 RPC_S_UNSUPPORTED_TRANS_SYN = 1730 RPC_S_UNSUPPORTED_TYPE = 1732 RPC_S_INVALID_TAG = 1733 RPC_S_INVALID_BOUND = 1734 RPC_S_NO_ENTRY_NAME = 1735 RPC_S_INVALID_NAME_SYNTAX = 1736 RPC_S_UNSUPPORTED_NAME_SYNTAX = 1737 RPC_S_UUID_NO_ADDRESS = 1739 RPC_S_DUPLICATE_ENDPOINT = 1740 RPC_S_UNKNOWN_AUTHN_TYPE = 1741 RPC_S_MAX_CALLS_TOO_SMALL = 1742 RPC_S_STRING_TOO_LONG = 1743 RPC_S_PROTSEQ_NOT_FOUND = 1744 RPC_S_PROCNUM_OUT_OF_RANGE = 1745 RPC_S_BINDING_HAS_NO_AUTH = 1746 RPC_S_UNKNOWN_AUTHN_SERVICE = 1747 RPC_S_UNKNOWN_AUTHN_LEVEL = 1748 RPC_S_INVALID_AUTH_IDENTITY = 1749 RPC_S_UNKNOWN_AUTHZ_SERVICE = 1750 EPT_S_INVALID_ENTRY = 1751 EPT_S_CANT_PERFORM_OP = 1752 EPT_S_NOT_REGISTERED = 1753 RPC_S_NOTHING_TO_EXPORT = 1754 RPC_S_INCOMPLETE_NAME = 1755 RPC_S_INVALID_VERS_OPTION = 1756 RPC_S_NO_MORE_MEMBERS = 1757 RPC_S_NOT_ALL_OBJS_UNEXPORTED = 1758 RPC_S_INTERFACE_NOT_FOUND = 1759 RPC_S_ENTRY_ALREADY_EXISTS = 1760 RPC_S_ENTRY_NOT_FOUND = 1761 RPC_S_NAME_SERVICE_UNAVAILABLE = 1762 RPC_S_INVALID_NAF_ID = 1763 RPC_S_CANNOT_SUPPORT = 1764 RPC_S_NO_CONTEXT_AVAILABLE = 1765 RPC_S_INTERNAL_ERROR = 1766 RPC_S_ZERO_DIVIDE = 1767 RPC_S_ADDRESS_ERROR = 1768 RPC_S_FP_DIV_ZERO = 1769 RPC_S_FP_UNDERFLOW = 1770 RPC_S_FP_OVERFLOW = 1771 RPC_X_NO_MORE_ENTRIES = 1772 RPC_X_SS_CHAR_TRANS_OPEN_FAIL = 1773 RPC_X_SS_CHAR_TRANS_SHORT_FILE = 1774 RPC_X_SS_IN_NULL_CONTEXT = 1775 RPC_X_SS_CONTEXT_DAMAGED = 1777 RPC_X_SS_HANDLES_MISMATCH = 1778 RPC_X_SS_CANNOT_GET_CALL_HANDLE = 1779 RPC_X_NULL_REF_POINTER = 1780 RPC_X_ENUM_VALUE_OUT_OF_RANGE = 1781 RPC_X_BYTE_COUNT_TOO_SMALL = 1782 RPC_X_BAD_STUB_DATA = 1783 ERROR_INVALID_USER_BUFFER = 1784 ERROR_UNRECOGNIZED_MEDIA = 1785 ERROR_NO_TRUST_LSA_SECRET = 1786 ERROR_NO_TRUST_SAM_ACCOUNT = 1787 ERROR_TRUSTED_DOMAIN_FAILURE = 1788 ERROR_TRUSTED_RELATIONSHIP_FAILURE = 1789 ERROR_TRUST_FAILURE = 1790 RPC_S_CALL_IN_PROGRESS = 1791 ERROR_NETLOGON_NOT_STARTED = 1792 ERROR_ACCOUNT_EXPIRED = 1793 ERROR_REDIRECTOR_HAS_OPEN_HANDLES = 1794 ERROR_PRINTER_DRIVER_ALREADY_INSTALLED= 1795 ERROR_UNKNOWN_PORT = 1796 ERROR_UNKNOWN_PRINTER_DRIVER = 1797 ERROR_UNKNOWN_PRINTPROCESSOR = 1798 ERROR_INVALID_SEPARATOR_FILE = 1799 ERROR_INVALID_PRIORITY = 1800 ERROR_INVALID_PRINTER_NAME = 1801 ERROR_PRINTER_ALREADY_EXISTS = 1802 ERROR_INVALID_PRINTER_COMMAND = 1803 ERROR_INVALID_DATATYPE = 1804 ERROR_INVALID_ENVIRONMENT = 1805 RPC_S_NO_MORE_BINDINGS = 1806 ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT = 1807 ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT = 1808 ERROR_NOLOGON_SERVER_TRUST_ACCOUNT = 1809 ERROR_DOMAIN_TRUST_INCONSISTENT = 1810 ERROR_SERVER_HAS_OPEN_HANDLES = 1811 ERROR_RESOURCE_DATA_NOT_FOUND = 1812 ERROR_RESOURCE_TYPE_NOT_FOUND = 1813 ERROR_RESOURCE_NAME_NOT_FOUND = 1814 ERROR_RESOURCE_LANG_NOT_FOUND = 1815 ERROR_NOT_ENOUGH_QUOTA = 1816 RPC_S_NO_INTERFACES = 1817 RPC_S_CALL_CANCELLED = 1818 RPC_S_BINDING_INCOMPLETE = 1819 RPC_S_COMM_FAILURE = 1820 RPC_S_UNSUPPORTED_AUTHN_LEVEL = 1821 RPC_S_NO_PRINC_NAME = 1822 RPC_S_NOT_RPC_ERROR = 1823 RPC_S_UUID_LOCAL_ONLY = 1824 RPC_S_SEC_PKG_ERROR = 1825 RPC_S_NOT_CANCELLED = 1826 RPC_X_INVALID_ES_ACTION = 1827 RPC_X_WRONG_ES_VERSION = 1828 RPC_X_WRONG_STUB_VERSION = 1829 RPC_X_INVALID_PIPE_OBJECT = 1830 RPC_X_WRONG_PIPE_ORDER = 1831 RPC_X_WRONG_PIPE_VERSION = 1832 RPC_S_GROUP_MEMBER_NOT_FOUND = 1898 EPT_S_CANT_CREATE = 1899 RPC_S_INVALID_OBJECT = 1900 ERROR_INVALID_TIME = 1901 ERROR_INVALID_FORM_NAME = 1902 ERROR_INVALID_FORM_SIZE = 1903 ERROR_ALREADY_WAITING = 1904 ERROR_PRINTER_DELETED = 1905 ERROR_INVALID_PRINTER_STATE = 1906 ERROR_PASSWORD_MUST_CHANGE = 1907 ERROR_DOMAIN_CONTROLLER_NOT_FOUND = 1908 ERROR_ACCOUNT_LOCKED_OUT = 1909 OR_INVALID_OXID = 1910 OR_INVALID_OID = 1911 OR_INVALID_SET = 1912 RPC_S_SEND_INCOMPLETE = 1913 RPC_S_INVALID_ASYNC_HANDLE = 1914 RPC_S_INVALID_ASYNC_CALL = 1915 RPC_X_PIPE_CLOSED = 1916 RPC_X_PIPE_DISCIPLINE_ERROR = 1917 RPC_X_PIPE_EMPTY = 1918 ERROR_NO_SITENAME = 1919 ERROR_CANT_ACCESS_FILE = 1920 ERROR_CANT_RESOLVE_FILENAME = 1921 RPC_S_ENTRY_TYPE_MISMATCH = 1922 RPC_S_NOT_ALL_OBJS_EXPORTED = 1923 RPC_S_INTERFACE_NOT_EXPORTED = 1924 RPC_S_PROFILE_NOT_ADDED = 1925 RPC_S_PRF_ELT_NOT_ADDED = 1926 RPC_S_PRF_ELT_NOT_REMOVED = 1927 RPC_S_GRP_ELT_NOT_ADDED = 1928 RPC_S_GRP_ELT_NOT_REMOVED = 1929 ERROR_KM_DRIVER_BLOCKED = 1930 ERROR_CONTEXT_EXPIRED = 1931 ERROR_PER_USER_TRUST_QUOTA_EXCEEDED = 1932 ERROR_ALL_USER_TRUST_QUOTA_EXCEEDED = 1933 ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED= 1934 ERROR_AUTHENTICATION_FIREWALL_FAILED = 1935 ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED= 1936 ERROR_INVALID_PIXEL_FORMAT = 2000 ERROR_BAD_DRIVER = 2001 ERROR_INVALID_WINDOW_STYLE = 2002 ERROR_METAFILE_NOT_SUPPORTED = 2003 ERROR_TRANSFORM_NOT_SUPPORTED = 2004 ERROR_CLIPPING_NOT_SUPPORTED = 2005 ERROR_INVALID_CMM = 2010 ERROR_INVALID_PROFILE = 2011 ERROR_TAG_NOT_FOUND = 2012 ERROR_TAG_NOT_PRESENT = 2013 ERROR_DUPLICATE_TAG = 2014 ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE = 2015 ERROR_PROFILE_NOT_FOUND = 2016 ERROR_INVALID_COLORSPACE = 2017 ERROR_ICM_NOT_ENABLED = 2018 ERROR_DELETING_ICM_XFORM = 2019 ERROR_INVALID_TRANSFORM = 2020 ERROR_COLORSPACE_MISMATCH = 2021 ERROR_INVALID_COLORINDEX = 2022 ERROR_CONNECTED_OTHER_PASSWORD = 2108 ERROR_BAD_USERNAME = 2202 ERROR_NOT_CONNECTED = 2250 ERROR_OPEN_FILES = 2401 ERROR_ACTIVE_CONNECTIONS = 2402 ERROR_DEVICE_IN_USE = 2404 ERROR_UNKNOWN_PRINT_MONITOR = 3000 ERROR_USER_DEFINED_BASE = 0xF000 # Flags for FormatMessage function: FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100 FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200 FORMAT_MESSAGE_FROM_STRING = 0x00000400 FORMAT_MESSAGE_FROM_HMODULE = 0x00000800 FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000 FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000 FORMAT_MESSAGE_MAX_WIDTH_MASK = 0x000000FF # Set/GetErrorMode values: SEM_FAILCRITICALERRORS = 0x0001 SEM_NOALIGNMENTFAULTEXCEPT = 0x0004 SEM_NOGPFAULTERRORBOX = 0x0002 SEM_NOOPENFILEERRORBOX = 0x8000 ############################################### # Win32 API Bindings ############################################### ffi_lib 'kernel32', 'user32' =begin DWORD WINAPI FormatMessage( __in DWORD dwFlags, __in_opt LPCVOID lpSource, __in DWORD dwMessageId, __in DWORD dwLanguageId, __out LPTSTR lpBuffer, __in DWORD nSize, __in_opt va_list *Arguments ); =end safe_attach_function :FormatMessageA, [:DWORD, :LPCVOID, :DWORD, :DWORD, :LPTSTR, :DWORD, :varargs], :DWORD safe_attach_function :FormatMessageW, [:DWORD, :LPCVOID, :DWORD, :DWORD, :LPWSTR, :DWORD, :varargs], :DWORD =begin DWORD WINAPI GetLastError(void); =end safe_attach_function :GetLastError, [], :DWORD =begin void WINAPI SetLastError( __in DWORD dwErrCode ); =end safe_attach_function :SetLastError, [:DWORD], :void safe_attach_function :SetLastErrorEx, [:DWORD, :DWORD], :void =begin UINT WINAPI GetErrorMode(void);s =end safe_attach_function :GetErrorMode, [], :uint =begin UINT WINAPI SetErrorMode( __in UINT uMode ); =end safe_attach_function :SetErrorMode, [:UINT], :UINT end end end end chef-11.8.2/lib/chef/win32/api.rb0000644000004100000410000005357612254362222016273 0ustar www-datawww-data# # Author:: Seth Chisamore () # Author:: John Keiser () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'ffi' require 'chef/reserved_names' require 'chef/exceptions' class Chef module ReservedNames::Win32 module API # Attempts to use FFI's attach_function method to link a native Win32 # function into the calling module. If this fails a dummy method is # defined which when called, raises a helpful exception to the end-user. def safe_attach_function(win32_func, *args) begin attach_function(win32_func.to_sym, *args) rescue FFI::NotFoundError define_method(win32_func.to_sym) do |*margs| raise Chef::Exceptions::Win32APIFunctionNotImplemented, "This version of Windows does not implement the Win32 function [#{win32_func}]." end end end # put shared stuff (like constants) for all raw Win32 API calls def self.extended(host) host.extend FFI::Library host.extend Macros host.ffi_convention :stdcall # Windows-specific type defs (ms-help://MS.MSDNQTR.v90.en/winprog/winprog/windows_data_types.htm): host.typedef :ushort, :ATOM # Atom ~= Symbol: Atom table stores strings and corresponding identifiers. Application # places a string in an atom table and receives a 16-bit integer, called an atom, that # can be used to access the string. Placed string is called an atom name. # See: http://msdn.microsoft.com/en-us/library/ms648708%28VS.85%29.aspx host.typedef :bool, :BOOL host.typedef :bool, :BOOLEAN host.typedef :uchar, :BYTE # Byte (8 bits). Declared as unsigned char #CALLBACK: K, # Win32.API gem-specific ?? MSDN: #define CALLBACK __stdcall host.typedef :char, :CHAR # 8-bit Windows (ANSI) character. See http://msdn.microsoft.com/en-us/library/dd183415%28VS.85%29.aspx host.typedef :uint32, :COLORREF # Red, green, blue (RGB) color value (32 bits). See COLORREF for more info. host.typedef :uint32, :DWORD # 32-bit unsigned integer. The range is 0 through 4,294,967,295 decimal. host.typedef :uint64, :DWORDLONG # 64-bit unsigned integer. The range is 0 through 18,446,744,073,709,551,615 decimal. host.typedef :ulong, :DWORD_PTR # Unsigned long type for pointer precision. Use when casting a pointer to a long type # to perform pointer arithmetic. (Also commonly used for general 32-bit parameters that have # been extended to 64 bits in 64-bit Windows.) BaseTsd.h: #host.typedef ULONG_PTR DWORD_PTR; host.typedef :uint32, :DWORD32 host.typedef :uint64, :DWORD64 host.typedef :int, :HALF_PTR # Half the size of a pointer. Use within a structure that contains a pointer and two small fields. # BaseTsd.h: #ifdef (_WIN64) host.typedef int HALF_PTR; #else host.typedef short HALF_PTR; host.typedef :ulong, :HACCEL # (L) Handle to an accelerator table. WinDef.h: #host.typedef HANDLE HACCEL; # See http://msdn.microsoft.com/en-us/library/ms645526%28VS.85%29.aspx host.typedef :ulong, :HANDLE # (L) Handle to an object. WinNT.h: #host.typedef PVOID HANDLE; # todo: Platform-dependent! Need to change to :uint64 for Win64 host.typedef :ulong, :HBITMAP # (L) Handle to a bitmap: http://msdn.microsoft.com/en-us/library/dd183377%28VS.85%29.aspx host.typedef :ulong, :HBRUSH # (L) Handle to a brush. http://msdn.microsoft.com/en-us/library/dd183394%28VS.85%29.aspx host.typedef :ulong, :HCOLORSPACE # (L) Handle to a color space. http://msdn.microsoft.com/en-us/library/ms536546%28VS.85%29.aspx host.typedef :ulong, :HCURSOR # (L) Handle to a cursor. http://msdn.microsoft.com/en-us/library/ms646970%28VS.85%29.aspx host.typedef :ulong, :HCONV # (L) Handle to a dynamic data exchange (DDE) conversation. host.typedef :ulong, :HCONVLIST # (L) Handle to a DDE conversation list. HANDLE - L ? host.typedef :ulong, :HDDEDATA # (L) Handle to DDE data (structure?) host.typedef :ulong, :HDC # (L) Handle to a device context (DC). http://msdn.microsoft.com/en-us/library/dd183560%28VS.85%29.aspx host.typedef :ulong, :HDESK # (L) Handle to a desktop. http://msdn.microsoft.com/en-us/library/ms682573%28VS.85%29.aspx host.typedef :ulong, :HDROP # (L) Handle to an internal drop structure. host.typedef :ulong, :HDWP # (L) Handle to a deferred window position structure. host.typedef :ulong, :HENHMETAFILE #(L) Handle to an enhanced metafile. http://msdn.microsoft.com/en-us/library/dd145051%28VS.85%29.aspx host.typedef :uint, :HFILE # (I) Special file handle to a file opened by OpenFile, not CreateFile. # WinDef.h: #host.typedef int HFILE; host.typedef :ulong, :HFONT # (L) Handle to a font. http://msdn.microsoft.com/en-us/library/dd162470%28VS.85%29.aspx host.typedef :ulong, :HGDIOBJ # (L) Handle to a GDI object. host.typedef :ulong, :HGLOBAL # (L) Handle to a global memory block. host.typedef :ulong, :HHOOK # (L) Handle to a hook. http://msdn.microsoft.com/en-us/library/ms632589%28VS.85%29.aspx host.typedef :ulong, :HICON # (L) Handle to an icon. http://msdn.microsoft.com/en-us/library/ms646973%28VS.85%29.aspx host.typedef :ulong, :HINSTANCE # (L) Handle to an instance. This is the base address of the module in memory. # HMODULE and HINSTANCE are the same today, but were different in 16-bit Windows. host.typedef :ulong, :HKEY # (L) Handle to a registry key. host.typedef :ulong, :HKL # (L) Input locale identifier. host.typedef :ulong, :HLOCAL # (L) Handle to a local memory block. host.typedef :ulong, :HMENU # (L) Handle to a menu. http://msdn.microsoft.com/en-us/library/ms646977%28VS.85%29.aspx host.typedef :ulong, :HMETAFILE # (L) Handle to a metafile. http://msdn.microsoft.com/en-us/library/dd145051%28VS.85%29.aspx host.typedef :ulong, :HMODULE # (L) Handle to an instance. Same as HINSTANCE today, but was different in 16-bit Windows. host.typedef :ulong, :HMONITOR # (L) Рandle to a display monitor. WinDef.h: if(WINVER >= 0x0500) host.typedef HANDLE HMONITOR; host.typedef :ulong, :HPALETTE # (L) Handle to a palette. host.typedef :ulong, :HPEN # (L) Handle to a pen. http://msdn.microsoft.com/en-us/library/dd162786%28VS.85%29.aspx host.typedef :long, :HRESULT # Return code used by COM interfaces. For more info, Structure of the COM Error Codes. # To test an HRESULT value, use the FAILED and SUCCEEDED macros. host.typedef :ulong, :HRGN # (L) Handle to a region. http://msdn.microsoft.com/en-us/library/dd162913%28VS.85%29.aspx host.typedef :ulong, :HRSRC # (L) Handle to a resource. host.typedef :ulong, :HSZ # (L) Handle to a DDE string. host.typedef :ulong, :HWINSTA # (L) Handle to a window station. http://msdn.microsoft.com/en-us/library/ms687096%28VS.85%29.aspx host.typedef :ulong, :HWND # (L) Handle to a window. http://msdn.microsoft.com/en-us/library/ms632595%28VS.85%29.aspx host.typedef :int, :INT # 32-bit signed integer. The range is -2147483648 through 2147483647 decimal. host.typedef :int, :INT_PTR # Signed integer type for pointer precision. Use when casting a pointer to an integer # to perform pointer arithmetic. BaseTsd.h: #if defined(_WIN64) host.typedef __int64 INT_PTR; #else host.typedef int INT_PTR; host.typedef :int32, :INT32 # 32-bit signed integer. The range is -2,147,483,648 through +...647 decimal. host.typedef :int64, :INT64 # 64-bit signed integer. The range is –9,223,372,036,854,775,808 through +...807 host.typedef :ushort, :LANGID # Language identifier. For more information, see Locales. WinNT.h: #host.typedef WORD LANGID; # See http://msdn.microsoft.com/en-us/library/dd318716%28VS.85%29.aspx host.typedef :uint32, :LCID # Locale identifier. For more information, see Locales. host.typedef :uint32, :LCTYPE # Locale information type. For a list, see Locale Information Constants. host.typedef :uint32, :LGRPID # Language group identifier. For a list, see EnumLanguageGroupLocales. host.typedef :long, :LONG # 32-bit signed integer. The range is -2,147,483,648 through +...647 decimal. host.typedef :int32, :LONG32 # 32-bit signed integer. The range is -2,147,483,648 through +...647 decimal. host.typedef :int64, :LONG64 # 64-bit signed integer. The range is –9,223,372,036,854,775,808 through +...807 host.typedef :int64, :LONGLONG # 64-bit signed integer. The range is –9,223,372,036,854,775,808 through +...807 host.typedef :long, :LONG_PTR # Signed long type for pointer precision. Use when casting a pointer to a long to # perform pointer arithmetic. BaseTsd.h: #if defined(_WIN64) host.typedef __int64 LONG_PTR; #else host.typedef long LONG_PTR; host.typedef :long, :LPARAM # Message parameter. WinDef.h as follows: #host.typedef LONG_PTR LPARAM; host.typedef :pointer, :LPBOOL # Pointer to a BOOL. WinDef.h as follows: #host.typedef BOOL far *LPBOOL; host.typedef :pointer, :LPBYTE # Pointer to a BYTE. WinDef.h as follows: #host.typedef BYTE far *LPBYTE; host.typedef :pointer, :LPCOLORREF # Pointer to a COLORREF value. WinDef.h as follows: #host.typedef DWORD *LPCOLORREF; host.typedef :pointer, :LPCSTR # Pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters. # See Character Sets Used By Fonts. http://msdn.microsoft.com/en-us/library/dd183415%28VS.85%29.aspx host.typedef :pointer, :LPCTSTR # An LPCWSTR if UNICODE is defined, an LPCSTR otherwise. host.typedef :pointer, :LPCVOID # Pointer to a constant of any type. WinDef.h as follows: host.typedef CONST void *LPCVOID; host.typedef :pointer, :LPCWSTR # Pointer to a constant null-terminated string of 16-bit Unicode characters. host.typedef :pointer, :LPDWORD # Pointer to a DWORD. WinDef.h as follows: host.typedef DWORD *LPDWORD; host.typedef :pointer, :LPHANDLE # Pointer to a HANDLE. WinDef.h as follows: host.typedef HANDLE *LPHANDLE; host.typedef :pointer, :LPINT # Pointer to an INT. host.typedef :pointer, :LPLONG # Pointer to an LONG. host.typedef :pointer, :LPSECURITY_ATTRIBUTES # Pointer to SECURITY_ATTRIBUTES struct host.typedef :pointer, :LPSTR # Pointer to a null-terminated string of 8-bit Windows (ANSI) characters. host.typedef :pointer, :LPTSTR # An LPWSTR if UNICODE is defined, an LPSTR otherwise. host.typedef :pointer, :LPVOID # Pointer to any type. host.typedef :pointer, :LPWORD # Pointer to a WORD. host.typedef :pointer, :LPWSTR # Pointer to a null-terminated string of 16-bit Unicode characters. host.typedef :long, :LRESULT # Signed result of message processing. WinDef.h: host.typedef LONG_PTR LRESULT; host.typedef :pointer, :LPWIN32_FIND_DATA # Pointer to WIN32_FIND_DATA struct host.typedef :pointer, :LPBY_HANDLE_FILE_INFORMATION # Point to a BY_HANDLE_FILE_INFORMATION struct host.typedef :pointer, :PBOOL # Pointer to a BOOL. host.typedef :pointer, :PBOOLEAN # Pointer to a BOOL. host.typedef :pointer, :PBYTE # Pointer to a BYTE. host.typedef :pointer, :PCHAR # Pointer to a CHAR. host.typedef :pointer, :PCSTR # Pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters. host.typedef :pointer, :PCTSTR # A PCWSTR if UNICODE is defined, a PCSTR otherwise. host.typedef :pointer, :PCWSTR # Pointer to a constant null-terminated string of 16-bit Unicode characters. host.typedef :pointer, :PDWORD # Pointer to a DWORD. host.typedef :pointer, :PDWORDLONG # Pointer to a DWORDLONG. host.typedef :pointer, :PDWORD_PTR # Pointer to a DWORD_PTR. host.typedef :pointer, :PDWORD32 # Pointer to a DWORD32. host.typedef :pointer, :PDWORD64 # Pointer to a DWORD64. host.typedef :pointer, :PFLOAT # Pointer to a FLOAT. host.typedef :pointer, :PHALF_PTR # Pointer to a HALF_PTR. host.typedef :pointer, :PHANDLE # Pointer to a HANDLE. host.typedef :pointer, :PHKEY # Pointer to an HKEY. host.typedef :pointer, :PINT # Pointer to an INT. host.typedef :pointer, :PINT_PTR # Pointer to an INT_PTR. host.typedef :pointer, :PINT32 # Pointer to an INT32. host.typedef :pointer, :PINT64 # Pointer to an INT64. host.typedef :pointer, :PLCID # Pointer to an LCID. host.typedef :pointer, :PLONG # Pointer to a LONG. host.typedef :pointer, :PLONGLONG # Pointer to a LONGLONG. host.typedef :pointer, :PLONG_PTR # Pointer to a LONG_PTR. host.typedef :pointer, :PLONG32 # Pointer to a LONG32. host.typedef :pointer, :PLONG64 # Pointer to a LONG64. host.typedef :pointer, :PLUID # Pointer to a LUID. host.typedef :pointer, :POINTER_32 # 32-bit pointer. On a 32-bit system, this is a native pointer. On a 64-bit system, this is a truncated 64-bit pointer. host.typedef :pointer, :POINTER_64 # 64-bit pointer. On a 64-bit system, this is a native pointer. On a 32-bit system, this is a sign-extended 32-bit pointer. host.typedef :pointer, :POINTER_SIGNED # A signed pointer. host.typedef :pointer, :POINTER_UNSIGNED # An unsigned pointer. host.typedef :pointer, :PSHORT # Pointer to a SHORT. host.typedef :pointer, :PSIZE_T # Pointer to a SIZE_T. host.typedef :pointer, :PSSIZE_T # Pointer to a SSIZE_T. host.typedef :pointer, :PSTR # Pointer to a null-terminated string of 8-bit Windows (ANSI) characters. For more information, see Character Sets Used By Fonts. host.typedef :pointer, :PTBYTE # Pointer to a TBYTE. host.typedef :pointer, :PTCHAR # Pointer to a TCHAR. host.typedef :pointer, :PTSTR # A PWSTR if UNICODE is defined, a PSTR otherwise. host.typedef :pointer, :PUCHAR # Pointer to a UCHAR. host.typedef :pointer, :PUHALF_PTR # Pointer to a UHALF_PTR. host.typedef :pointer, :PUINT # Pointer to a UINT. host.typedef :pointer, :PUINT_PTR # Pointer to a UINT_PTR. host.typedef :pointer, :PUINT32 # Pointer to a UINT32. host.typedef :pointer, :PUINT64 # Pointer to a UINT64. host.typedef :pointer, :PULONG # Pointer to a ULONG. host.typedef :pointer, :PULONGLONG # Pointer to a ULONGLONG. host.typedef :pointer, :PULONG_PTR # Pointer to a ULONG_PTR. host.typedef :pointer, :PULONG32 # Pointer to a ULONG32. host.typedef :pointer, :PULONG64 # Pointer to a ULONG64. host.typedef :pointer, :PUSHORT # Pointer to a USHORT. host.typedef :pointer, :PVOID # Pointer to any type. host.typedef :pointer, :PWCHAR # Pointer to a WCHAR. host.typedef :pointer, :PWORD # Pointer to a WORD. host.typedef :pointer, :PWSTR # Pointer to a null- terminated string of 16-bit Unicode characters. # For more information, see Character Sets Used By Fonts. host.typedef :ulong, :SC_HANDLE # (L) Handle to a service control manager database. # See SCM Handles http://msdn.microsoft.com/en-us/library/ms685104%28VS.85%29.aspx host.typedef :pointer, :SC_LOCK # Lock to a service control manager database. For more information, see SCM Handles. host.typedef :ulong, :SERVICE_STATUS_HANDLE # (L) Handle to a service status value. See SCM Handles. host.typedef :short, :SHORT # A 16-bit integer. The range is –32768 through 32767 decimal. host.typedef :ulong, :SIZE_T # The maximum number of bytes to which a pointer can point. Use for a count that must span the full range of a pointer. host.typedef :long, :SSIZE_T # Signed SIZE_T. host.typedef :char, :TBYTE # A WCHAR if UNICODE is defined, a CHAR otherwise.TCHAR: # http://msdn.microsoft.com/en-us/library/c426s321%28VS.80%29.aspx host.typedef :char, :TCHAR # A WCHAR if UNICODE is defined, a CHAR otherwise.TCHAR: host.typedef :uchar, :UCHAR # Unsigned CHAR (8 bit) host.typedef :uint, :UHALF_PTR # Unsigned HALF_PTR. Use within a structure that contains a pointer and two small fields. host.typedef :uint, :UINT # Unsigned INT. The range is 0 through 4294967295 decimal. host.typedef :uint, :UINT_PTR # Unsigned INT_PTR. host.typedef :uint32, :UINT32 # Unsigned INT32. The range is 0 through 4294967295 decimal. host.typedef :uint64, :UINT64 # Unsigned INT64. The range is 0 through 18446744073709551615 decimal. host.typedef :ulong, :ULONG # Unsigned LONG. The range is 0 through 4294967295 decimal. host.typedef :ulong_long, :ULONGLONG # 64-bit unsigned integer. The range is 0 through 18446744073709551615 decimal. host.typedef :ulong, :ULONG_PTR # Unsigned LONG_PTR. host.typedef :uint32, :ULONG32 # Unsigned INT32. The range is 0 through 4294967295 decimal. host.typedef :uint64, :ULONG64 # Unsigned LONG64. The range is 0 through 18446744073709551615 decimal. host.typedef :pointer, :UNICODE_STRING # Pointer to some string structure?? host.typedef :ushort, :USHORT # Unsigned SHORT. The range is 0 through 65535 decimal. host.typedef :ulong_long, :USN # Update sequence number (USN). host.typedef :ushort, :WCHAR # 16-bit Unicode character. For more information, see Character Sets Used By Fonts. # In WinNT.h: host.typedef wchar_t WCHAR; #WINAPI: K, # Calling convention for system functions. WinDef.h: define WINAPI __stdcall host.typedef :ushort, :WORD # 16-bit unsigned integer. The range is 0 through 65535 decimal. host.typedef :uint, :WPARAM # Message parameter. WinDef.h as follows: host.typedef UINT_PTR WPARAM; end module Macros ############################################### # winbase.h ############################################### def LocalDiscard(pointer) LocalReAlloc(pointer, 0, LMEM_MOVEABLE) end ############################################### # windef.h ############################################### # Creates a WORD value by concatenating the specified values. # # http://msdn.microsoft.com/en-us/library/windows/desktop/ms632663(v=VS.85).aspx def MAKEWORD(low, high) ((low & 0xff) | (high & 0xff)) << 8 end # Creates a LONG value by concatenating the specified values. # # http://msdn.microsoft.com/en-us/library/windows/desktop/ms632660(v=vs.85).aspx def MAKELONG(low, high) ((low & 0xffff) | (high & 0xffff)) << 16 end # Retrieves the low-order word from the specified value. # # http://msdn.microsoft.com/en-us/library/windows/desktop/ms632659(v=VS.85).aspx def LOWORD(l) l & 0xffff end # Retrieves the high-order word from the specified 32-bit value. # # http://msdn.microsoft.com/en-us/library/windows/desktop/ms632657(v=VS.85).aspx def HIWORD(l) l >> 16 end # Retrieves the low-order byte from the specified value. # # http://msdn.microsoft.com/en-us/library/windows/desktop/ms632658(v=VS.85).aspx def LOBYTE(w) w & 0xff end # Retrieves the high-order byte from the given 16-bit value. # # http://msdn.microsoft.com/en-us/library/windows/desktop/ms632656(v=VS.85).aspx def HIBYTE(w) w >> 8 end ############################################### # winerror.h ############################################### def IS_ERROR(status) status >> 31 == 1 end def MAKE_HRESULT(sev, fac, code) sev << 31 | fac << 16 | code end def MAKE_SCODE(sev, fac, code) sev << 31 | fac << 16 | code end def HRESULT_CODE(hr) hr & 0xFFFF end def HRESULT_FACILITY(hr) (hr >> 16) & 0x1fff end def HRESULT_FROM_NT(x) x | 0x10000000 # FACILITY_NT_BIT end def HRESULT_FROM_WIN32(x) if x <= 0 x else (x & 0x0000FFFF) | (7 << 16) | 0x80000000 end end def HRESULT_SEVERITY(hr) (hr >> 31) & 0x1 end def FAILED(status) status < 0 end def SUCCEEDED(status) status >= 0 end end # Represents a 64-bit unsigned integer value. # # http://msdn.microsoft.com/en-us/library/windows/desktop/aa383742(v=vs.85).aspx def make_uint64(low, high) low + (high * (2**32)) end # http://blogs.msdn.com/b/oldnewthing/archive/2009/03/06/9461176.aspx # January 1, 1601 WIN32_EPOC_MINUS_POSIX_EPOC = 116444736000000000 # Convert 64-bit FILETIME integer into Time object. # # FILETIME structure contains a 64-bit value representing the number # of 100-nanosecond intervals since January 1, 1601 (UTC). # # http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx # def wtime_to_time(wtime) Time.at((wtime - WIN32_EPOC_MINUS_POSIX_EPOC) / 10000000) end end end end chef-11.8.2/lib/chef/win32/file.rb0000644000004100000410000001352412254362222016426 0ustar www-datawww-data# # Author:: Seth Chisamore () # Author:: Mark Mzyk () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/api/file' require 'chef/win32/api/security' require 'chef/win32/error' class Chef module ReservedNames::Win32 class File include Chef::ReservedNames::Win32::API::File extend Chef::ReservedNames::Win32::API::File # Creates a symbolic link called +new_name+ for the file or directory # +old_name+. # # This method requires Windows Vista or later to work. Otherwise, it # returns nil as per MRI. # def self.link(old_name, new_name) raise Errno::ENOENT, "(#{old_name}, #{new_name})" unless ::File.exist?(old_name) # TODO do a check for CreateHardLinkW and # raise NotImplemented exception on older Windows old_name = encode_path(old_name) new_name = encode_path(new_name) unless CreateHardLinkW(new_name, old_name, nil) Chef::ReservedNames::Win32::Error.raise! end end # Creates a symbolic link called +new_name+ for the file or directory # +old_name+. # # This method requires Windows Vista or later to work. Otherwise, it # returns nil as per MRI. # def self.symlink(old_name, new_name) # raise Errno::ENOENT, "(#{old_name}, #{new_name})" unless ::File.exist?(old_name) # TODO do a check for CreateSymbolicLinkW and # raise NotImplemented exception on older Windows flags = ::File.directory?(old_name) ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0 old_name = encode_path(old_name) new_name = encode_path(new_name) unless CreateSymbolicLinkW(new_name, old_name, flags) Chef::ReservedNames::Win32::Error.raise! end end # Return true if the named file is a symbolic link, false otherwise. # # This method requires Windows Vista or later to work. Otherwise, it # always returns false as per MRI. # def self.symlink?(file_name) is_symlink = false path = encode_path(file_name) if ::File.exists?(file_name) if ((GetFileAttributesW(path) & FILE_ATTRIBUTE_REPARSE_POINT) > 0) file_search_handle(file_name) do |handle, find_data| if find_data[:dw_reserved_0] == IO_REPARSE_TAG_SYMLINK is_symlink = true end end end end is_symlink end # Returns the path of the of the symbolic link referred to by +file+. # # Requires Windows Vista or later. On older versions of Windows it # will raise a NotImplementedError, as per MRI. # def self.readlink(link_name) raise Errno::ENOENT, link_name unless ::File.exists?(link_name) symlink_file_handle(link_name) do |handle| # Go to DeviceIoControl to get the symlink information # http://msdn.microsoft.com/en-us/library/windows/desktop/aa364571(v=vs.85).aspx reparse_buffer = FFI::MemoryPointer.new(MAXIMUM_REPARSE_DATA_BUFFER_SIZE) parsed_size = FFI::Buffer.new(:long).write_long(0) if DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, nil, 0, reparse_buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, parsed_size, nil) == 0 Chef::ReservedNames::Win32::Error.raise! end # Ensure it's a symbolic link reparse_buffer = REPARSE_DATA_BUFFER.new(reparse_buffer) if reparse_buffer[:ReparseTag] != IO_REPARSE_TAG_SYMLINK raise Errno::EACCES, "#{link_name} is not a symlink" end # Return the link destination (strip off \??\ at the beginning, which is a local filesystem thing) link_dest = reparse_buffer.reparse_buffer.substitute_name if link_dest =~ /^\\\?\?\\/ link_dest = link_dest[4..-1] end link_dest end end # Gets the short form of a path (Administrator -> ADMINI~1) def self.get_short_path_name(path) path = path.to_wstring size = GetShortPathNameW(path, nil, 0) if size == 0 Chef::ReservedNames::Win32::Error.raise! end result = FFI::MemoryPointer.new :char, (size+1)*2 if GetShortPathNameW(path, result, size+1) == 0 Chef::ReservedNames::Win32::Error.raise! end result.read_wstring(size) end # Gets the long form of a path (ADMINI~1 -> Administrator) def self.get_long_path_name(path) path = path.to_wstring size = GetLongPathNameW(path, nil, 0) if size == 0 Chef::ReservedNames::Win32::Error.raise! end result = FFI::MemoryPointer.new :char, (size+1)*2 if GetLongPathNameW(path, result, size+1) == 0 Chef::ReservedNames::Win32::Error.raise! end result.read_wstring(size) end def self.info(file_name) Info.new(file_name) end def self.verify_links_supported! begin CreateSymbolicLinkW(nil) rescue Chef::Exceptions::Win32APIFunctionNotImplemented => e raise e rescue Exception # things are ok. end end # ::File compat class << self alias :stat :info end end end end require 'chef/win32/file/info' chef-11.8.2/lib/chef/win32/version.rb0000644000004100000410000001254112254362222017172 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/api' require 'chef/win32/api/system' class Chef module ReservedNames::Win32 class Version include Chef::ReservedNames::Win32::API::Macros include Chef::ReservedNames::Win32::API::System # Ruby implementation of # http://msdn.microsoft.com/en-us/library/ms724833(v=vs.85).aspx # http://msdn.microsoft.com/en-us/library/ms724358(v=vs.85).aspx private def self.get_system_metrics(n_index) Win32API.new('user32', 'GetSystemMetrics', 'I', 'I').call(n_index) end public WIN_VERSIONS = { "Windows 8.1" => {:major => 6, :minor => 3, :callable => lambda{ @product_type == VER_NT_WORKSTATION }}, "Windows Server 2012 R2" => {:major => 6, :minor => 3, :callable => lambda{ @product_type != VER_NT_WORKSTATION }}, "Windows 8" => {:major => 6, :minor => 2, :callable => lambda{ @product_type == VER_NT_WORKSTATION }}, "Windows Server 2012" => {:major => 6, :minor => 2, :callable => lambda{ @product_type != VER_NT_WORKSTATION }}, "Windows 7" => {:major => 6, :minor => 1, :callable => lambda{ @product_type == VER_NT_WORKSTATION }}, "Windows Server 2008 R2" => {:major => 6, :minor => 1, :callable => lambda{ @product_type != VER_NT_WORKSTATION }}, "Windows Server 2008" => {:major => 6, :minor => 0, :callable => lambda{ @product_type != VER_NT_WORKSTATION }}, "Windows Vista" => {:major => 6, :minor => 0, :callable => lambda{ @product_type == VER_NT_WORKSTATION }}, "Windows Server 2003 R2" => {:major => 5, :minor => 2, :callable => lambda{ get_system_metrics(SM_SERVERR2) != 0 }}, "Windows Home Server" => {:major => 5, :minor => 2, :callable => lambda{ (@suite_mask & VER_SUITE_WH_SERVER) == VER_SUITE_WH_SERVER }}, "Windows Server 2003" => {:major => 5, :minor => 2, :callable => lambda{ get_system_metrics(SM_SERVERR2) == 0 }}, "Windows XP" => {:major => 5, :minor => 1}, "Windows 2000" => {:major => 5, :minor => 0} } def initialize @major_version, @minor_version, @build_number = get_version ver_info = get_version_ex @product_type = ver_info[:w_product_type] @suite_mask = ver_info[:w_suite_mask] @sp_major_version = ver_info[:w_service_pack_major] @sp_minor_version = ver_info[:w_service_pack_minor] # Obtain sku information for the purpose of identifying # datacenter, cluster, and core skus, the latter 2 only # exist in releases after Windows Server 2003 if ! Chef::Platform::windows_server_2003? @sku = get_product_info(@major_version, @minor_version, @sp_major_version, @sp_minor_version) else # The get_product_info API is not supported on Win2k3, # use an alternative to identify datacenter skus @sku = get_datacenter_product_info_windows_server_2003(ver_info) end end marketing_names = Array.new # General Windows checks WIN_VERSIONS.each do |k,v| method_name = "#{k.gsub(/\s/, '_').downcase}?" define_method(method_name) do (@major_version == v[:major]) && (@minor_version == v[:minor]) && (v[:callable] ? v[:callable].call : true) end marketing_names << [k, method_name] end define_method(:marketing_name) do marketing_names.each do |mn| break mn[0] if self.send(mn[1]) end end # Server Type checks %w{ cluster core datacenter }.each do |m| define_method("#{m}?") do self.class.constants.any? do |c| (self.class.const_get(c) == @sku) && (c.to_s =~ /#{m}/i ) end end end private def get_version version = GetVersion() major = LOBYTE(LOWORD(version)) minor = HIBYTE(LOWORD(version)) build = version < 0x80000000 ? HIWORD(version) : 0 [major, minor, build] end def get_version_ex lp_version_info = OSVERSIONINFOEX.new lp_version_info[:dw_os_version_info_size] = OSVERSIONINFOEX.size unless GetVersionExW(lp_version_info) Chef::ReservedNames::Win32::Error.raise! end lp_version_info end def get_product_info(major, minor, sp_major, sp_minor) out = FFI::MemoryPointer.new(:uint32) GetProductInfo(major, minor, sp_major, sp_minor, out) out.get_uint(0) end def get_datacenter_product_info_windows_server_2003(ver_info) # The intent is not to get the actual sku, just identify # Windows Server 2003 datacenter sku = (ver_info[:w_suite_mask] & VER_SUITE_DATACENTER) ? PRODUCT_DATACENTER_SERVER : 0 end end end end chef-11.8.2/lib/chef/win32/unicode.rb0000644000004100000410000000230312254362222017126 0ustar www-datawww-data# # Author:: John Keiser () # Author:: Seth Chisamore () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/api/unicode' class Chef module ReservedNames::Win32 class Unicode include Chef::ReservedNames::Win32::API::Unicode extend Chef::ReservedNames::Win32::API::Unicode end end end module FFI class Pointer def read_wstring(num_wchars) Chef::ReservedNames::Win32::Unicode.wide_to_utf8(self.get_bytes(0, num_wchars*2)) end end end class String def to_wstring Chef::ReservedNames::Win32::Unicode.utf8_to_wide(self) end end chef-11.8.2/lib/chef/win32/registry.rb0000644000004100000410000003302512254362222017355 0ustar www-datawww-data# # Author:: Prajakta Purohit () # Author:: Lamont Granquist () # # Copyright:: 2012, 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. # require 'chef/reserved_names' if RUBY_PLATFORM =~ /mswin|mingw32|windows/ require 'win32/registry' require 'ruby-wmi' require 'win32/api' end class Chef class Win32 class Registry attr_accessor :run_context attr_accessor :architecture def initialize(run_context=nil, user_architecture=:machine) @run_context = run_context self.architecture = user_architecture end def architecture=(user_architecture) @architecture = user_architecture.to_sym assert_architecture! end def get_values(key_path) hive, key = get_hive_and_key(key_path) key_exists!(key_path) values = hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg| reg.map { |name, type, data| {:name=>name, :type=>get_name_from_type(type), :data=>data} } end end def set_value(key_path, value) Chef::Log.debug("Updating value #{value[:name]} in registry key #{key_path} with type #{value[:type]} and data #{value[:data]}") key_exists!(key_path) hive, key = get_hive_and_key(key_path) if value_exists?(key_path, value) if data_exists?(key_path, value) Chef::Log.debug("Value #{value[:name]} in registry key #{key_path} already had those values, not updated") return false else hive.open(key, ::Win32::Registry::KEY_SET_VALUE | ::Win32::Registry::KEY_QUERY_VALUE | registry_system_architecture) do |reg| reg.write(value[:name], get_type_from_name(value[:type]), value[:data]) end Chef::Log.debug("Value #{value[:name]} in registry key #{key_path} updated") end else hive.open(key, ::Win32::Registry::KEY_SET_VALUE | ::Win32::Registry::KEY_QUERY_VALUE | registry_system_architecture) do |reg| reg.write(value[:name], get_type_from_name(value[:type]), value[:data]) end Chef::Log.debug("Value #{value[:name]} in registry key #{key_path} created") end true end def delete_value(key_path, value) Chef::Log.debug("Deleting value #{value[:name]} from registry key #{key_path}") if value_exists?(key_path, value) begin hive, key = get_hive_and_key(key_path) rescue Chef::Exceptions::Win32RegKeyMissing return true end hive.open(key, ::Win32::Registry::KEY_SET_VALUE | registry_system_architecture) do |reg| reg.delete_value(value[:name]) Chef::Log.debug("Deleted value #{value[:name]} from registry key #{key_path}") end else Chef::Log.debug("Value #{value[:name]} in registry key #{key_path} does not exist, not updated") end true end def create_key(key_path, recursive) Chef::Log.debug("Creating registry key #{key_path}") if keys_missing?(key_path) if recursive == true Chef::Log.debug("Registry key #{key_path} has missing subkeys, and recursive specified, creating them....") create_missing(key_path) else raise Chef::Exceptions::Win32RegNoRecursive, "Registry key #{key_path} has missing subkeys, and recursive not specified" end end if key_exists?(key_path) Chef::Log.debug("Registry key #{key_path} already exists, doing nothing") else hive, key = get_hive_and_key(key_path) hive.create(key, ::Win32::Registry::KEY_WRITE | registry_system_architecture) Chef::Log.debug("Registry key #{key_path} created") end true end def delete_key(key_path, recursive) Chef::Log.debug("Deleting registry key #{key_path}") unless key_exists?(key_path) Chef::Log.debug("Registry key #{key_path}, does not exist, not deleting") return true end #key_path is in the form "HKLM\Software\Opscode" for example, extracting #hive = HKLM, #hive_namespace = ::Win32::Registry::HKEY_LOCAL_MACHINE hive = key_path.split("\\").shift hive_namespace, key_including_parent = get_hive_and_key(key_path) if has_subkeys?(key_path) if recursive == true subkeys = get_subkeys(key_path) subkeys.each do |key| keypath_to_check = hive+"\\"+key_including_parent+"\\"+key Chef::Log.debug("Deleting registry key #{key_path} recursively") delete_key(keypath_to_check, true) end delete_key_ex(hive_namespace, key_including_parent) else raise Chef::Exceptions::Win32RegNoRecursive, "Registry key #{key_path} has subkeys, and recursive not specified" end else delete_key_ex(hive_namespace, key_including_parent) return true end true end #Using the 'RegDeleteKeyEx' Windows API that correctly supports WOW64 systems (Win2003) #instead of the 'RegDeleteKey' def delete_key_ex(hive, key) regDeleteKeyEx = ::Win32::API.new('RegDeleteKeyEx', 'LPLL', 'L', 'advapi32') hive_num = hive.hkey - (1 << 32) regDeleteKeyEx.call(hive_num, key, ::Win32::Registry::KEY_WRITE | registry_system_architecture, 0) end def key_exists?(key_path) hive, key = get_hive_and_key(key_path) begin hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |current_key| return true end rescue ::Win32::Registry::Error => e return false end end def key_exists!(key_path) unless key_exists?(key_path) raise Chef::Exceptions::Win32RegKeyMissing, "Registry key #{key_path} does not exist" end true end def hive_exists?(key_path) begin hive, key = get_hive_and_key(key_path) rescue Chef::Exceptions::Win32RegHiveMissing => e return false end return true end def has_subkeys?(key_path) key_exists!(key_path) hive, key = get_hive_and_key(key_path) hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg| reg.each_key{ |key| return true } end return false end def get_subkeys(key_path) subkeys = [] key_exists!(key_path) hive, key = get_hive_and_key(key_path) hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg| reg.each_key{ |current_key| subkeys << current_key } end return subkeys end # 32-bit chef clients running on 64-bit machines will default to reading the 64-bit registry def registry_system_architecture applied_arch = ( architecture == :machine ) ? machine_architecture : architecture ( applied_arch == :x86_64 ) ? 0x0100 : 0x0200 end def value_exists?(key_path, value) key_exists!(key_path) hive, key = get_hive_and_key(key_path) hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg| return true if reg.any? {|val| val == value[:name] } end return false end def data_exists?(key_path, value) key_exists!(key_path) hive, key = get_hive_and_key(key_path) hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg| reg.each do |val_name, val_type, val_data| if val_name == value[:name] && val_type == get_type_from_name(value[:type]) && val_data == value[:data] return true end end end return false end def value_exists!(key_path, value) unless value_exists?(key_path, value) raise Chef::Exceptions::Win32RegValueMissing, "Registry key #{key_path} has no value named #{value[:name]}" end true end def data_exists!(key_path, value) unless data_exists?(key_path, value) raise Chef::Exceptions::Win32RegDataMissing, "Registry key #{key_path} has no value named #{value[:name]}, containing type #{value[:type]} and data #{value[:data]}" end true end def type_matches?(key_path, value) value_exists!(key_path, value) hive, key = get_hive_and_key(key_path) hive.open(key, ::Win32::Registry::KEY_READ | registry_system_architecture) do |reg| reg.each do |val_name, val_type| if val_name == value[:name] type_new = get_type_from_name(value[:type]) if val_type == type_new return true end end end end return false end def type_matches!(key_path, value) unless type_matches?(key_path, value) raise Chef::Exceptions::Win32RegTypesMismatch, "Registry key #{key_path} has a value #{value[:name]} with a type that is not #{value[:type]}" end end def get_type_from_name(val_type) value = { :binary => ::Win32::Registry::REG_BINARY, :string => ::Win32::Registry::REG_SZ, :multi_string => ::Win32::Registry::REG_MULTI_SZ, :expand_string => ::Win32::Registry::REG_EXPAND_SZ, :dword => ::Win32::Registry::REG_DWORD, :dword_big_endian => ::Win32::Registry::REG_DWORD_BIG_ENDIAN, :qword => ::Win32::Registry::REG_QWORD }[val_type] return value end def keys_missing?(key_path) missing_key_arr = key_path.split("\\") missing_key_arr.pop key = missing_key_arr.join("\\") !key_exists?(key) end def get_type_from_name(val_type) _type_name_map[val_type] end def get_name_from_type(val_class) _name_type_map[val_class] end private def node run_context && run_context.node end def machine_architecture node[:kernel][:machine].to_sym end def assert_architecture! if machine_architecture == :i386 && architecture == :x86_64 raise Chef::Exceptions::Win32RegArchitectureIncorrect, "cannot access 64-bit registry on a 32-bit windows instance" end end def get_hive_and_key(path) reg_path = path.split("\\") hive_name = reg_path.shift key = reg_path.join("\\") hive = { "HKLM" => ::Win32::Registry::HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE" => ::Win32::Registry::HKEY_LOCAL_MACHINE, "HKU" => ::Win32::Registry::HKEY_USERS, "HKEY_USERS" => ::Win32::Registry::HKEY_USERS, "HKCU" => ::Win32::Registry::HKEY_CURRENT_USER, "HKEY_CURRENT_USER" => ::Win32::Registry::HKEY_CURRENT_USER, "HKCR" => ::Win32::Registry::HKEY_CLASSES_ROOT, "HKEY_CLASSES_ROOT" => ::Win32::Registry::HKEY_CLASSES_ROOT, "HKCC" => ::Win32::Registry::HKEY_CURRENT_CONFIG, "HKEY_CURRENT_CONFIG" => ::Win32::Registry::HKEY_CURRENT_CONFIG, }[hive_name] raise Chef::Exceptions::Win32RegHiveMissing, "Registry Hive #{hive_name} does not exist" unless hive return hive, key end def _type_name_map { :binary => ::Win32::Registry::REG_BINARY, :string => ::Win32::Registry::REG_SZ, :multi_string => ::Win32::Registry::REG_MULTI_SZ, :expand_string => ::Win32::Registry::REG_EXPAND_SZ, :dword => ::Win32::Registry::REG_DWORD, :dword_big_endian => ::Win32::Registry::REG_DWORD_BIG_ENDIAN, :qword => ::Win32::Registry::REG_QWORD } end def _name_type_map @_name_type_map ||= _type_name_map.invert end def get_type_from_num(val_type) value = { 3 => ::Win32::Registry::REG_BINARY, 1 => ::Win32::Registry::REG_SZ, 7 => ::Win32::Registry::REG_MULTI_SZ, 2 => ::Win32::Registry::REG_EXPAND_SZ, 4 => ::Win32::Registry::REG_DWORD, 5 => ::Win32::Registry::REG_DWORD_BIG_ENDIAN, 11 => ::Win32::Registry::REG_QWORD }[val_type] return value end def create_missing(key_path) missing_key_arr = key_path.split("\\") hivename = missing_key_arr.shift missing_key_arr.pop existing_key_path = hivename hive, key = get_hive_and_key(key_path) missing_key_arr.each do |intermediate_key| existing_key_path = existing_key_path << "\\" << intermediate_key if !key_exists?(existing_key_path) Chef::Log.debug("Recursively creating registry key #{existing_key_path}") hive.create(get_key(existing_key_path), ::Win32::Registry::KEY_ALL_ACCESS | registry_system_architecture) end end end def get_key(path) reg_path = path.split("\\") hive_name = reg_path.shift key = reg_path.join("\\") end end end end chef-11.8.2/lib/chef/win32/error.rb0000644000004100000410000000507312254362222016640 0ustar www-datawww-data# # Author:: John Keiser () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/api/error' require 'chef/win32/memory' require 'chef/win32/unicode' require 'chef/exceptions' class Chef module ReservedNames::Win32 class Error include Chef::ReservedNames::Win32::API::Error extend Chef::ReservedNames::Win32::API::Error def self.format_message(message_id = 0, args = {}) flags = args[:flags] || FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY source = args[:source] language_id = args[:language_id] || 0 varargs = args[:varargs] || [:int, 0] buffer = FFI::MemoryPointer.new :pointer num_chars = FormatMessageW(flags | FORMAT_MESSAGE_ALLOCATE_BUFFER, source, message_id, language_id, buffer, 0, *varargs) if num_chars == 0 raise! end # Extract the string begin return buffer.read_pointer.read_wstring(num_chars) ensure Chef::ReservedNames::Win32::Memory.local_free(buffer.read_pointer) end end def self.get_last_error GetLastError() end # Raises the last error. This should only be called by # Win32 API wrapper functions, and then only when wrapped # in an if() statement (since it unconditionally exits) # === Returns # nil::: always returns nil when it does not raise # === Raises # Chef::Exceptions::Win32APIError::: def self.raise!(message = nil) code = get_last_error msg = format_message(code).strip formatted_message = "" formatted_message << message if message formatted_message << "---- Begin Win32 API output ----\n" formatted_message << "System Error Code: #{code}\n" formatted_message << "System Error Message: #{msg}\n" formatted_message << "---- End Win32 API output ----\n" raise Chef::Exceptions::Win32APIError, msg + "\n" + formatted_message end end end end chef-11.8.2/lib/chef/shell_out.rb0000644000004100000410000000054112254362222016536 0ustar www-datawww-datarequire 'mixlib/shellout' class Chef class ShellOut < Mixlib::ShellOut def initialize(*args) Chef::Log.warn("Chef::ShellOut is deprecated, please use Mixlib::ShellOut") called_from = caller[0..3].inject("Called from:\n") {|msg, trace_line| msg << " #{trace_line}\n" } Chef::Log.warn(called_from) super end end end chef-11.8.2/lib/chef/run_context.rb0000644000004100000410000001771512254362222017123 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Walters () # Author:: Tim Hinderliter () # Copyright:: Copyright (c) 2008-2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'chef/resource_collection' require 'chef/cookbook_version' require 'chef/node' require 'chef/role' require 'chef/log' require 'chef/recipe' require 'chef/run_context/cookbook_compiler' class Chef # == Chef::RunContext # Value object that loads and tracks the context of a Chef run class RunContext # Chef::Node object for this run attr_reader :node # Chef::CookbookCollection for this run attr_reader :cookbook_collection # Resource Definitions for this run. Populated when the files in # +definitions/+ are evaluated (this is triggered by #load). attr_reader :definitions ### # These need to be settable so deploy can run a resource_collection # independent of any cookbooks via +recipe_eval+ # The Chef::ResourceCollection for this run. Populated by evaluating # recipes, which is triggered by #load. (See also: CookbookCompiler) attr_accessor :resource_collection # A Hash containing the immediate notifications triggered by resources # during the converge phase of the chef run. attr_accessor :immediate_notification_collection # A Hash containing the delayed (end of run) notifications triggered by # resources during the converge phase of the chef run. attr_accessor :delayed_notification_collection # Event dispatcher for this run. attr_reader :events # Creates a new Chef::RunContext object and populates its fields. This object gets # used by the Chef Server to generate a fully compiled recipe list for a node. # # === Returns # object:: Duh. :) def initialize(node, cookbook_collection, events) @node = node @cookbook_collection = cookbook_collection @resource_collection = Chef::ResourceCollection.new @immediate_notification_collection = Hash.new {|h,k| h[k] = []} @delayed_notification_collection = Hash.new {|h,k| h[k] = []} @definitions = Hash.new @loaded_recipes = {} @loaded_attributes = {} @events = events @node.run_context = self end # Triggers the compile phase of the chef run. Implemented by # Chef::RunContext::CookbookCompiler def load(run_list_expansion) compiler = CookbookCompiler.new(self, run_list_expansion, events) compiler.compile end # Adds an immediate notification to the # +immediate_notification_collection+. The notification should be a # Chef::Resource::Notification or duck type. def notifies_immediately(notification) nr = notification.notifying_resource if nr.instance_of?(Chef::Resource) @immediate_notification_collection[nr.name] << notification else @immediate_notification_collection[nr.to_s] << notification end end # Adds a delayed notification to the +delayed_notification_collection+. The # notification should be a Chef::Resource::Notification or duck type. def notifies_delayed(notification) nr = notification.notifying_resource if nr.instance_of?(Chef::Resource) @delayed_notification_collection[nr.name] << notification else @delayed_notification_collection[nr.to_s] << notification end end def immediate_notifications(resource) if resource.instance_of?(Chef::Resource) return @immediate_notification_collection[resource.name] else return @immediate_notification_collection[resource.to_s] end end def delayed_notifications(resource) if resource.instance_of?(Chef::Resource) return @delayed_notification_collection[resource.name] else return @delayed_notification_collection[resource.to_s] end end # Evaluates the recipes +recipe_names+. Used by DSL::IncludeRecipe def include_recipe(*recipe_names) result_recipes = Array.new recipe_names.flatten.each do |recipe_name| if result = load_recipe(recipe_name) result_recipes << result end end result_recipes end # Evaluates the recipe +recipe_name+. Used by DSL::IncludeRecipe def load_recipe(recipe_name) Chef::Log.debug("Loading Recipe #{recipe_name} via include_recipe") cookbook_name, recipe_short_name = Chef::Recipe.parse_recipe_name(recipe_name) if loaded_fully_qualified_recipe?(cookbook_name, recipe_short_name) Chef::Log.debug("I am not loading #{recipe_name}, because I have already seen it.") false else loaded_recipe(cookbook_name, recipe_short_name) cookbook = cookbook_collection[cookbook_name] cookbook.load_recipe(recipe_short_name, self) end end # Looks up an attribute file given the +cookbook_name+ and # +attr_file_name+. Used by DSL::IncludeAttribute def resolve_attribute(cookbook_name, attr_file_name) cookbook = cookbook_collection[cookbook_name] raise Chef::Exceptions::CookbookNotFound, "could not find cookbook #{cookbook_name} while loading attribute #{name}" unless cookbook attribute_filename = cookbook.attribute_filenames_by_short_filename[attr_file_name] raise Chef::Exceptions::AttributeNotFound, "could not find filename for attribute #{attr_file_name} in cookbook #{cookbook_name}" unless attribute_filename attribute_filename end # An Array of all recipes that have been loaded. This is stored internally # as a Hash, so ordering is not preserved when using ruby 1.8. # # Recipe names are given in fully qualified form, e.g., the recipe "nginx" # will be given as "nginx::default" # # To determine if a particular recipe has been loaded, use #loaded_recipe? def loaded_recipes @loaded_recipes.keys end # An Array of all attributes files that have been loaded. Stored internally # using a Hash, so order is not preserved on ruby 1.8. # # Attribute file names are given in fully qualified form, e.g., # "nginx::default" instead of "nginx". def loaded_attributes @loaded_attributes.keys end def loaded_fully_qualified_recipe?(cookbook, recipe) @loaded_recipes.has_key?("#{cookbook}::#{recipe}") end # Returns true if +recipe+ has been loaded, false otherwise. Default recipe # names are expanded, so `loaded_recipe?("nginx")` and # `loaded_recipe?("nginx::default")` are valid and give identical results. def loaded_recipe?(recipe) cookbook, recipe_name = Chef::Recipe.parse_recipe_name(recipe) loaded_fully_qualified_recipe?(cookbook, recipe_name) end def loaded_fully_qualified_attribute?(cookbook, attribute_file) @loaded_attributes.has_key?("#{cookbook}::#{attribute_file}") end def loaded_attribute(cookbook, attribute_file) @loaded_attributes["#{cookbook}::#{attribute_file}"] = true end ## # Cookbook File Introspection def has_template_in_cookbook?(cookbook, template_name) cookbook = cookbook_collection[cookbook] cookbook.has_template_for_node?(node, template_name) end def has_cookbook_file_in_cookbook?(cookbook, cb_file_name) cookbook = cookbook_collection[cookbook] cookbook.has_cookbook_file_for_node?(node, cb_file_name) end private def loaded_recipe(cookbook, recipe) @loaded_recipes["#{cookbook}::#{recipe}"] = true end end end chef-11.8.2/lib/chef/chef_fs.rb0000644000004100000410000000017212254362222016135 0ustar www-datawww-datarequire 'chef/platform' class Chef module ChefFS def self.windows? Chef::Platform.windows? end end end chef-11.8.2/lib/chef/monologger.rb0000644000004100000410000000367212254362222016720 0ustar www-datawww-datarequire 'logger' require 'pp' #== MonoLogger # A subclass of Ruby's stdlib Logger with all the mutex and logrotation stuff # ripped out. class MonoLogger < Logger # # === Synopsis # # Logger.new(name, shift_age = 7, shift_size = 1048576) # Logger.new(name, shift_age = 'weekly') # # === Args # # +logdev+:: # The log device. This is a filename (String) or IO object (typically # +STDOUT+, +STDERR+, or an open file). # +shift_age+:: # Number of old log files to keep, *or* frequency of rotation (+daily+, # +weekly+ or +monthly+). # +shift_size+:: # Maximum logfile size (only applies when +shift_age+ is a number). # # === Description # # Create an instance. # def initialize(logdev) @progname = nil @level = DEBUG @default_formatter = Formatter.new @formatter = nil @logdev = nil if logdev @logdev = LocklessLogDevice.new(logdev) end end class LocklessLogDevice < LogDevice def initialize(log = nil) @dev = @filename = @shift_age = @shift_size = nil if log.respond_to?(:write) and log.respond_to?(:close) @dev = log else @dev = open_logfile(log) @dev.sync = true @filename = log end end def write(message) @dev.write(message) rescue Exception => ignored warn("log writing failed. #{ignored}") end def close @dev.close rescue nil end private def open_logfile(filename) if (FileTest.exist?(filename)) open(filename, (File::WRONLY | File::APPEND)) else create_logfile(filename) end end def create_logfile(filename) logdev = open(filename, (File::WRONLY | File::APPEND | File::CREAT)) logdev.sync = true add_log_header(logdev) logdev end def add_log_header(file) file.write( "# Logfile created on %s by %s\n" % [Time.now.to_s, Logger::ProgName] ) end end end chef-11.8.2/lib/chef/cookbook/0000755000004100000410000000000012254362222016021 5ustar www-datawww-datachef-11.8.2/lib/chef/cookbook/chefignore.rb0000644000004100000410000000361512254362222020464 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Cookbook class Chefignore COMMENTS_AND_WHITESPACE = /^\s*(?:#.*)?$/ attr_reader :ignores def initialize(ignore_file_or_repo) @ignore_file = find_ignore_file(ignore_file_or_repo) @ignores = parse_ignore_file end def remove_ignores_from(file_list) Array(file_list).inject([]) do |unignored, file| ignored?(file) ? unignored : unignored << file end end def ignored?(file_name) @ignores.any? {|glob| File.fnmatch?(glob, file_name)} end private def parse_ignore_file ignore_globs = [] if File.exist?(@ignore_file) && File.readable?(@ignore_file) && (File.file?(@ignore_file) || File.symlink?(@ignore_file)) File.foreach(@ignore_file) do |line| ignore_globs << line.strip unless line =~ COMMENTS_AND_WHITESPACE end else Chef::Log.debug("No chefignore file found at #@ignore_file no files will be ignored") end ignore_globs end def find_ignore_file(path) if File.basename(path) =~ /chefignore/ path else File.join(path, 'chefignore') end end end end end chef-11.8.2/lib/chef/cookbook/metadata.rb0000644000004100000410000005553212254362222020140 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: AJ Christensen () # Author:: Seth Falcon () # Copyright:: Copyright 2008-2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/mash' require 'chef/mixin/from_file' require 'chef/mixin/params_validate' require 'chef/log' require 'chef/version_class' require 'chef/version_constraint' class Chef class Cookbook # == Chef::Cookbook::Metadata # Chef::Cookbook::Metadata provides a convenient DSL for declaring metadata # about Chef Cookbooks. class Metadata NAME = 'name'.freeze DESCRIPTION = 'description'.freeze LONG_DESCRIPTION = 'long_description'.freeze MAINTAINER = 'maintainer'.freeze MAINTAINER_EMAIL = 'maintainer_email'.freeze LICENSE = 'license'.freeze PLATFORMS = 'platforms'.freeze DEPENDENCIES = 'dependencies'.freeze RECOMMENDATIONS = 'recommendations'.freeze SUGGESTIONS = 'suggestions'.freeze CONFLICTING = 'conflicting'.freeze PROVIDING = 'providing'.freeze REPLACING = 'replacing'.freeze ATTRIBUTES = 'attributes'.freeze GROUPINGS = 'groupings'.freeze RECIPES = 'recipes'.freeze VERSION = 'version'.freeze COMPARISON_FIELDS = [ :name, :description, :long_description, :maintainer, :maintainer_email, :license, :platforms, :dependencies, :recommendations, :suggestions, :conflicting, :providing, :replacing, :attributes, :groupings, :recipes, :version] VERSION_CONSTRAINTS = {:depends => DEPENDENCIES, :recommends => RECOMMENDATIONS, :suggests => SUGGESTIONS, :conflicts => CONFLICTING, :provides => PROVIDING, :replaces => REPLACING } include Chef::Mixin::ParamsValidate include Chef::Mixin::FromFile attr_reader :cookbook, :platforms, :dependencies, :recommendations, :suggestions, :conflicting, :providing, :replacing, :attributes, :groupings, :recipes, :version # Builds a new Chef::Cookbook::Metadata object. # # === Parameters # cookbook:: An optional cookbook object # maintainer:: An optional maintainer # maintainer_email:: An optional maintainer email # license::An optional license. Default is Apache v2.0 # # === Returns # metadata def initialize(cookbook=nil, maintainer='YOUR_COMPANY_NAME', maintainer_email='YOUR_EMAIL', license='none') @cookbook = cookbook @name = cookbook ? cookbook.name : "" @long_description = "" self.maintainer(maintainer) self.maintainer_email(maintainer_email) self.license(license) self.description('A fabulous new cookbook') @platforms = Mash.new @dependencies = Mash.new @recommendations = Mash.new @suggestions = Mash.new @conflicting = Mash.new @providing = Mash.new @replacing = Mash.new @attributes = Mash.new @groupings = Mash.new @recipes = Mash.new @version = Version.new "0.0.0" if cookbook @recipes = cookbook.fully_qualified_recipe_names.inject({}) do |r, e| e = self.name.to_s if e =~ /::default$/ r[e] ||= "" self.provides e r end end end def ==(other) COMPARISON_FIELDS.inject(true) do |equal_so_far, field| equal_so_far && other.respond_to?(field) && (other.send(field) == send(field)) end end # Sets the cookbooks maintainer, or returns it. # # === Parameters # maintainer:: The maintainers name # # === Returns # maintainer:: Returns the current maintainer. def maintainer(arg=nil) set_or_return( :maintainer, arg, :kind_of => [ String ] ) end # Sets the maintainers email address, or returns it. # # === Parameters # maintainer_email:: The maintainers email address # # === Returns # maintainer_email:: Returns the current maintainer email. def maintainer_email(arg=nil) set_or_return( :maintainer_email, arg, :kind_of => [ String ] ) end # Sets the current license, or returns it. # # === Parameters # license:: The current license. # # === Returns # license:: Returns the current license def license(arg=nil) set_or_return( :license, arg, :kind_of => [ String ] ) end # Sets the current description, or returns it. Should be short - one line only! # # === Parameters # description:: The new description # # === Returns # description:: Returns the description def description(arg=nil) set_or_return( :description, arg, :kind_of => [ String ] ) end # Sets the current long description, or returns it. Might come from a README, say. # # === Parameters # long_description:: The new long description # # === Returns # long_description:: Returns the long description def long_description(arg=nil) set_or_return( :long_description, arg, :kind_of => [ String ] ) end # Sets the current cookbook version, or returns it. Can be two or three digits, seperated # by dots. ie: '2.1', '1.5.4' or '0.9'. # # === Parameters # version:: The curent version, as a string # # === Returns # version:: Returns the current version def version(arg=nil) if arg @version = Chef::Version.new(arg) end @version.to_s end # Sets the name of the cookbook, or returns it. # # === Parameters # name:: The curent cookbook name. # # === Returns # name:: Returns the current cookbook name. def name(arg=nil) set_or_return( :name, arg, :kind_of => [ String ] ) end # Adds a supported platform, with version checking strings. # # === Parameters # platform,:: The platform (like :ubuntu or :mac_os_x) # version:: A version constraint of the form "OP VERSION", # where OP is one of < <= = > >= ~> and VERSION has # the form x.y.z or x.y. # # === Returns # versions:: Returns the list of versions for the platform def supports(platform, *version_args) version = new_args_format(:supports, platform, version_args) validate_version_constraint(:supports, platform, version) @platforms[platform] = version @platforms[platform] end # Adds a dependency on another cookbook, with version checking strings. # # === Parameters # cookbook:: The cookbook # version:: A version constraint of the form "OP VERSION", # where OP is one of < <= = > >= ~> and VERSION has # the form x.y.z or x.y. # # === Returns # versions:: Returns the list of versions for the platform def depends(cookbook, *version_args) version = new_args_format(:depends, cookbook, version_args) validate_version_constraint(:depends, cookbook, version) @dependencies[cookbook] = version @dependencies[cookbook] end # Adds a recommendation for another cookbook, with version checking strings. # # === Parameters # cookbook:: The cookbook # version:: A version constraint of the form "OP VERSION", # where OP is one of < <= = > >= ~> and VERSION has # the form x.y.z or x.y. # # === Returns # versions:: Returns the list of versions for the platform def recommends(cookbook, *version_args) version = new_args_format(:recommends, cookbook, version_args) validate_version_constraint(:recommends, cookbook, version) @recommendations[cookbook] = version @recommendations[cookbook] end # Adds a suggestion for another cookbook, with version checking strings. # # === Parameters # cookbook:: The cookbook # version:: A version constraint of the form "OP VERSION", # where OP is one of < <= = > >= ~> and VERSION has the # formx.y.z or x.y. # # === Returns # versions:: Returns the list of versions for the platform def suggests(cookbook, *version_args) version = new_args_format(:suggests, cookbook, version_args) validate_version_constraint(:suggests, cookbook, version) @suggestions[cookbook] = version @suggestions[cookbook] end # Adds a conflict for another cookbook, with version checking strings. # # === Parameters # cookbook:: The cookbook # version:: A version constraint of the form "OP VERSION", # where OP is one of < <= = > >= ~> and VERSION has # the form x.y.z or x.y. # # === Returns # versions:: Returns the list of versions for the platform def conflicts(cookbook, *version_args) version = new_args_format(:conflicts, cookbook, version_args) validate_version_constraint(:conflicts, cookbook, version) @conflicting[cookbook] = version @conflicting[cookbook] end # Adds a recipe, definition, or resource provided by this cookbook. # # Recipes are specified as normal # Definitions are followed by (), and can include :params for prototyping # Resources are the stringified version (service[apache2]) # # === Parameters # recipe, definition, resource:: The thing we provide # version:: A version constraint of the form "OP VERSION", # where OP is one of < <= = > >= ~> and VERSION has # the form x.y.z or x.y. # # === Returns # versions:: Returns the list of versions for the platform def provides(cookbook, *version_args) version = new_args_format(:provides, cookbook, version_args) validate_version_constraint(:provides, cookbook, version) @providing[cookbook] = version @providing[cookbook] end # Adds a cookbook that is replaced by this one, with version checking strings. # # === Parameters # cookbook:: The cookbook we replace # version:: A version constraint of the form "OP VERSION", # where OP is one of < <= = > >= ~> and VERSION has the form x.y.z or x.y. # # === Returns # versions:: Returns the list of versions for the platform def replaces(cookbook, *version_args) version = new_args_format(:replaces, cookbook, version_args) validate_version_constraint(:replaces, cookbook, version) @replacing[cookbook] = version @replacing[cookbook] end # Adds a description for a recipe. # # === Parameters # recipe:: The recipe # description:: The description of the recipe # # === Returns # description:: Returns the current description def recipe(name, description) @recipes[name] = description end # Adds an attribute )hat a user needs to configure for this cookbook. Takes # a name (with the / notation for a nested attribute), followed by any of # these options # # display_name:: What a UI should show for this attribute # description:: A hint as to what this attr is for # choice:: An array of choices to present to the user. # calculated:: If true, the default value is calculated by the recipe and cannot be displayed. # type:: "string" or "array" - default is "string" ("hash" is supported for backwards compatibility) # required:: Whether this attr is 'required', 'recommended' or 'optional' - default 'optional' (true/false values also supported for backwards compatibility) # recipes:: An array of recipes which need this attr set. # default,,:: The default value # # === Parameters # name:: The name of the attribute ('foo', or 'apache2/log_dir') # options:: The description of the options # # === Returns # options:: Returns the current options hash def attribute(name, options) validate( options, { :display_name => { :kind_of => String }, :description => { :kind_of => String }, :choice => { :kind_of => [ Array ], :default => [] }, :calculated => { :equal_to => [ true, false ], :default => false }, :type => { :equal_to => [ "string", "array", "hash", "symbol" ], :default => "string" }, :required => { :equal_to => [ "required", "recommended", "optional", true, false ], :default => "optional" }, :recipes => { :kind_of => [ Array ], :default => [] }, :default => { :kind_of => [ String, Array, Hash ] } } ) options[:required] = remap_required_attribute(options[:required]) unless options[:required].nil? validate_string_array(options[:choice]) validate_calculated_default_rule(options) validate_choice_default_rule(options) @attributes[name] = options @attributes[name] end def grouping(name, options) validate( options, { :title => { :kind_of => String }, :description => { :kind_of => String } } ) @groupings[name] = options @groupings[name] end def to_hash { NAME => self.name, DESCRIPTION => self.description, LONG_DESCRIPTION => self.long_description, MAINTAINER => self.maintainer, MAINTAINER_EMAIL => self.maintainer_email, LICENSE => self.license, PLATFORMS => self.platforms, DEPENDENCIES => self.dependencies, RECOMMENDATIONS => self.recommendations, SUGGESTIONS => self.suggestions, CONFLICTING => self.conflicting, PROVIDING => self.providing, REPLACING => self.replacing, ATTRIBUTES => self.attributes, GROUPINGS => self.groupings, RECIPES => self.recipes, VERSION => self.version } end def to_json(*a) self.to_hash.to_json(*a) end def self.from_hash(o) cm = self.new() cm.from_hash(o) cm end def from_hash(o) @name = o[NAME] if o.has_key?(NAME) @description = o[DESCRIPTION] if o.has_key?(DESCRIPTION) @long_description = o[LONG_DESCRIPTION] if o.has_key?(LONG_DESCRIPTION) @maintainer = o[MAINTAINER] if o.has_key?(MAINTAINER) @maintainer_email = o[MAINTAINER_EMAIL] if o.has_key?(MAINTAINER_EMAIL) @license = o[LICENSE] if o.has_key?(LICENSE) @platforms = o[PLATFORMS] if o.has_key?(PLATFORMS) @dependencies = handle_deprecated_constraints(o[DEPENDENCIES]) if o.has_key?(DEPENDENCIES) @recommendations = handle_deprecated_constraints(o[RECOMMENDATIONS]) if o.has_key?(RECOMMENDATIONS) @suggestions = handle_deprecated_constraints(o[SUGGESTIONS]) if o.has_key?(SUGGESTIONS) @conflicting = handle_deprecated_constraints(o[CONFLICTING]) if o.has_key?(CONFLICTING) @providing = o[PROVIDING] if o.has_key?(PROVIDING) @replacing = handle_deprecated_constraints(o[REPLACING]) if o.has_key?(REPLACING) @attributes = o[ATTRIBUTES] if o.has_key?(ATTRIBUTES) @groupings = o[GROUPINGS] if o.has_key?(GROUPINGS) @recipes = o[RECIPES] if o.has_key?(RECIPES) @version = o[VERSION] if o.has_key?(VERSION) self end def self.from_json(string) o = Chef::JSONCompat.from_json(string) self.from_hash(o) end def self.validate_json(json_str) o = Chef::JSONCompat.from_json(json_str) metadata = new() VERSION_CONSTRAINTS.each do |method_name, hash_key| if constraints = o[hash_key] constraints.each do |cb_name, constraints| metadata.send(method_name, cb_name, *Array(constraints)) end end end true end def from_json(string) o = Chef::JSONCompat.from_json(string) from_hash(o) end private def new_args_format(caller_name, dep_name, version_constraints) if version_constraints.empty? ">= 0.0.0" elsif version_constraints.size == 1 version_constraints.first else msg=<<-OBSOLETED The dependency specification syntax you are using is no longer valid. You may not specify more than one version constraint for a particular cookbook. Consult http://wiki.opscode.com/display/chef/Metadata for the updated syntax. Called by: #{caller_name} '#{dep_name}', #{version_constraints.map {|vc| vc.inspect}.join(", ")} Called from: #{caller[0...5].map {|line| " " + line}.join("\n")} OBSOLETED raise Exceptions::ObsoleteDependencySyntax, msg end end def validate_version_constraint(caller_name, dep_name, constraint_str) Chef::VersionConstraint.new(constraint_str) rescue Chef::Exceptions::InvalidVersionConstraint => e Log.debug(e) msg=<<-INVALID The version constraint syntax you are using is not valid. If you recently upgraded to Chef 0.10.0, be aware that you no may longer use "<<" and ">>" for 'less than' and 'greater than'; use '<' and '>' instead. Consult http://wiki.opscode.com/display/chef/Metadata for more information. Called by: #{caller_name} '#{dep_name}', '#{constraint_str}' Called from: #{caller[0...5].map {|line| " " + line}.join("\n")} INVALID raise Exceptions::InvalidVersionConstraint, msg end # Verify that the given array is an array of strings # # Raise an exception if the members of the array are not Strings # # === Parameters # arry:: An array to be validated def validate_string_array(arry) if arry.kind_of?(Array) arry.each do |choice| validate( {:choice => choice}, {:choice => {:kind_of => String}} ) end end end # For backwards compatibility, remap Boolean values to String # true is mapped to "required" # false is mapped to "optional" # # === Parameters # required_attr:: The value of options[:required] # # === Returns # required_attr:: "required", "recommended", or "optional" def remap_required_attribute(value) case value when true value = "required" when false value = "optional" end value end def validate_calculated_default_rule(options) calculated_conflict = ((options[:default].is_a?(Array) && !options[:default].empty?) || (options[:default].is_a?(String) && !options[:default] != "")) && options[:calculated] == true raise ArgumentError, "Default cannot be specified if calculated is true!" if calculated_conflict end def validate_choice_default_rule(options) return if !options[:choice].is_a?(Array) || options[:choice].empty? if options[:default].is_a?(String) && options[:default] != "" raise ArgumentError, "Default must be one of your choice values!" if options[:choice].index(options[:default]) == nil end if options[:default].is_a?(Array) && !options[:default].empty? options[:default].each do |val| raise ArgumentError, "Default values must be a subset of your choice values!" if options[:choice].index(val) == nil end end end # This method translates version constraint strings from # cookbooks with the old format. # # Before we began respecting version constraints, we allowed # multiple constraints to be placed on cookbooks, as well as the # << and >> operators, which are now just < and >. For # specifications with more than one constraint, we return an # empty array (otherwise, we're silently abiding only part of # the contract they have specified to us). If there is only one # constraint, we are replacing the old << and >> with the new < # and >. def handle_deprecated_constraints(specification) specification.inject(Mash.new) do |acc, (cb, constraints)| constraints = Array(constraints) acc[cb] = (constraints.empty? || constraints.size > 1) ? [] : constraints.first.gsub(/>>/, '>').gsub(/<) # Author:: Tim Hinderliter () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/cookbook/file_vendor' class Chef class Cookbook # == Chef::Cookbook::FileSystemFileVendor # This FileVendor loads files from Chef::Config.cookbook_path. The # thing that's sort of janky about this FileVendor implementation is # that it basically takes only the cookbook's name from the manifest # and throws the rest away then re-builds the list of files on the # disk. This is due to the manifest not having the on-disk file # locations, since in the chef-client case, that information is # non-sensical. class FileSystemFileVendor < FileVendor def initialize(manifest, *repo_paths) @cookbook_name = manifest[:cookbook_name] @repo_paths = repo_paths.flatten raise ArgumentError, "You must specify at least one repo path" if @repo_paths.empty? end # Implements abstract base's requirement. It looks in the # Chef::Config.cookbook_path file hierarchy for the requested # file. def get_filename(filename) location = @repo_paths.inject(nil) do |memo, basepath| candidate_location = File.join(basepath, @cookbook_name, filename) memo = candidate_location if File.exist?(candidate_location) memo end raise "File #{filename} does not exist for cookbook #{@cookbook_name}" unless location location end end end end chef-11.8.2/lib/chef/cookbook/synchronizer.rb0000644000004100000410000001517312254362222021112 0ustar www-datawww-datarequire 'chef/client' require 'singleton' class Chef # Keep track of the filenames that we use in both eager cookbook # downloading (during sync_cookbooks) and lazy (during the run # itself, through FileVendor). After the run is over, clean up the # cache. class CookbookCacheCleaner # Setup a notification to clear the valid_cache_entries when a Chef client # run starts Chef::Client.when_run_starts do |run_status| instance.reset! end # Register a notification to cleanup unused files from cookbooks Chef::Client.when_run_completes_successfully do |run_status| instance.cleanup_file_cache end include Singleton def initialize reset! end def reset! @valid_cache_entries = {} end def mark_file_as_valid(cache_path) @valid_cache_entries[cache_path] = true end def cache Chef::FileCache end def cleanup_file_cache unless Chef::Config[:solo] # Delete each file in the cache that we didn't encounter in the # manifest. cache.find(File.join(%w{cookbooks ** *})).each do |cache_filename| unless @valid_cache_entries[cache_filename] Chef::Log.info("Removing #{cache_filename} from the cache; it is no longer needed by chef-client.") cache.delete(cache_filename) end end end end end # Synchronizes the locally cached copies of cookbooks with the files on the # server. class CookbookSynchronizer def initialize(cookbooks_by_name, events) @eager_segments = Chef::CookbookVersion::COOKBOOK_SEGMENTS.dup unless Chef::Config[:no_lazy_load] @eager_segments.delete(:files) @eager_segments.delete(:templates) end @eager_segments.freeze @cookbooks_by_name, @events = cookbooks_by_name, events end def cache Chef::FileCache end def cookbook_names @cookbooks_by_name.keys end def cookbooks @cookbooks_by_name.values end def cookbook_count @cookbooks_by_name.size end def have_cookbook?(cookbook_name) @cookbooks_by_name.key?(cookbook_name) end # Synchronizes all the cookbooks from the chef-server. #) # === Returns # true:: Always returns true def sync_cookbooks Chef::Log.info("Loading cookbooks [#{cookbook_names.sort.join(', ')}]") Chef::Log.debug("Cookbooks detail: #{cookbooks.inspect}") clear_obsoleted_cookbooks @events.cookbook_sync_start(cookbook_count) # Synchronize each of the node's cookbooks, and add to the # valid_cache_entries hash. cookbooks.each do |cookbook| sync_cookbook(cookbook) end rescue Exception => e @events.cookbook_sync_failed(cookbooks, e) raise else @events.cookbook_sync_complete true end # Iterates over cached cookbooks' files, removing files belonging to # cookbooks that don't appear in +cookbook_hash+ def clear_obsoleted_cookbooks @events.cookbook_clean_start # Remove all cookbooks no longer relevant to this node cache.find(File.join(%w{cookbooks ** *})).each do |cache_file| cache_file =~ /^cookbooks\/([^\/]+)\// unless have_cookbook?($1) Chef::Log.info("Removing #{cache_file} from the cache; its cookbook is no longer needed on this client.") cache.delete(cache_file) @events.removed_cookbook_file(cache_file) end end @events.cookbook_clean_complete end # Sync the eagerly loaded files contained by +cookbook+ # # === Arguments # cookbook:: The cookbook to update # valid_cache_entries:: Out-param; Added to this hash are the files that # were referred to by this cookbook def sync_cookbook(cookbook) Chef::Log.debug("Synchronizing cookbook #{cookbook.name}") # files and templates are lazily loaded, and will be done later. @eager_segments.each do |segment| segment_filenames = Array.new cookbook.manifest[segment].each do |manifest_record| cache_filename = sync_file_in_cookbook(cookbook, manifest_record) # make the segment filenames a full path. full_path_cache_filename = cache.load(cache_filename, false) segment_filenames << full_path_cache_filename end # replace segment filenames with a full-path one. if segment.to_sym == :recipes cookbook.recipe_filenames = segment_filenames elsif segment.to_sym == :attributes cookbook.attribute_filenames = segment_filenames else cookbook.segment_filenames(segment).replace(segment_filenames) end end @events.synchronized_cookbook(cookbook.name) end # Sync an individual file if needed. If there is an up to date copy # locally, nothing is done. # # === Arguments # file_manifest::: A Hash of the form {"path" => 'relative/path', "url" => "location to fetch the file"} # === Returns # Path to the cached file as a String def sync_file_in_cookbook(cookbook, file_manifest) cache_filename = File.join("cookbooks", cookbook.name, file_manifest['path']) mark_cached_file_valid(cache_filename) # If the checksums are different between on-disk (current) and on-server # (remote, per manifest), do the update. This will also execute if there # is no current checksum. if !cached_copy_up_to_date?(cache_filename, file_manifest['checksum']) download_file(file_manifest['url'], cache_filename) @events.updated_cookbook_file(cookbook.name, cache_filename) else Chef::Log.debug("Not storing #{cache_filename}, as the cache is up to date.") end cache_filename end def cached_copy_up_to_date?(local_path, expected_checksum) if cache.has_key?(local_path) current_checksum = CookbookVersion.checksum_cookbook_file(cache.load(local_path, false)) expected_checksum == current_checksum else false end end # Unconditionally download the file from the given URL. File will be # downloaded to the path +destination+ which is relative to the Chef file # cache root. def download_file(url, destination) raw_file = server_api.get_rest(url, true) Chef::Log.info("Storing updated #{destination} in the cache.") cache.move_to(raw_file.path, destination) end # Marks the given file as valid (non-stale). def mark_cached_file_valid(cache_filename) CookbookCacheCleaner.instance.mark_file_as_valid(cache_filename) end def server_api Chef::REST.new(Chef::Config[:chef_server_url]) end end end chef-11.8.2/lib/chef/cookbook/syntax_check.rb0000644000004100000410000001365112254362222021037 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'pathname' require 'chef/mixin/shell_out' require 'chef/mixin/checksum' class Chef class Cookbook # == Chef::Cookbook::SyntaxCheck # Encapsulates the process of validating the ruby syntax of files in Chef # cookbooks. class SyntaxCheck # == Chef::Cookbook::SyntaxCheck::PersistentSet # Implements set behavior with disk-based persistence. Objects in the set # are expected to be strings containing only characters that are valid in # filenames. # # This class is used to track which files have been syntax checked so # that known good files are not rechecked. class PersistentSet attr_reader :cache_path # Create a new PersistentSet. Values in the set are persisted by # creating a file in the +cache_path+ directory. def initialize(cache_path=Chef::Config[:syntax_check_cache_path]) @cache_path = cache_path @cache_path_created = false end # Adds +value+ to the set's collection. def add(value) ensure_cache_path_created FileUtils.touch(File.join(cache_path, value)) end # Returns true if the set includes +value+ def include?(value) File.exist?(File.join(cache_path, value)) end private def ensure_cache_path_created return true if @cache_path_created FileUtils.mkdir_p(cache_path) @cache_path_created = true end end include Chef::Mixin::ShellOut include Chef::Mixin::Checksum attr_reader :cookbook_path # A PersistentSet object that tracks which files have already been # validated. attr_reader :validated_files # Creates a new SyntaxCheck given the +cookbook_name+ and a +cookbook_path+. # If no +cookbook_path+ is given, +Chef::Config.cookbook_path+ is used. def self.for_cookbook(cookbook_name, cookbook_path=nil) cookbook_path ||= Chef::Config.cookbook_path unless cookbook_path raise ArgumentError, "Cannot find cookbook #{cookbook_name} unless Chef::Config.cookbook_path is set or an explicit cookbook path is given" end new(File.join(cookbook_path, cookbook_name.to_s)) end # Create a new SyntaxCheck object # === Arguments # cookbook_path::: the (on disk) path to the cookbook def initialize(cookbook_path) @cookbook_path = cookbook_path @validated_files = PersistentSet.new end def chefignore @chefignore ||= Chefignore.new(File.dirname(cookbook_path)) end def remove_ignored_files(file_list) return file_list unless chefignore.ignores.length > 0 file_list.reject do |full_path| cookbook_pn = Pathname.new cookbook_path full_pn = Pathname.new full_path relative_pn = full_pn.relative_path_from cookbook_pn chefignore.ignored? relative_pn.to_s end end def ruby_files remove_ignored_files Dir[File.join(cookbook_path, '**', '*.rb')] end def untested_ruby_files ruby_files.reject do |file| if validated?(file) Chef::Log.debug("Ruby file #{file} is unchanged, skipping syntax check") true else false end end end def template_files remove_ignored_files Dir[File.join(cookbook_path, '**', '*.erb')] end def untested_template_files template_files.reject do |file| if validated?(file) Chef::Log.debug("Template #{file} is unchanged, skipping syntax check") true else false end end end def validated?(file) validated_files.include?(checksum(file)) end def validated(file) validated_files.add(checksum(file)) end def validate_ruby_files untested_ruby_files.each do |ruby_file| return false unless validate_ruby_file(ruby_file) validated(ruby_file) end end def validate_templates untested_template_files.each do |template| return false unless validate_template(template) validated(template) end end def validate_template(erb_file) Chef::Log.debug("Testing template #{erb_file} for syntax errors...") result = shell_out("erubis -x #{erb_file} | ruby -c") result.error! true rescue Mixlib::ShellOut::ShellCommandFailed file_relative_path = erb_file[/^#{Regexp.escape(cookbook_path+File::Separator)}(.*)/, 1] Chef::Log.fatal("Erb template #{file_relative_path} has a syntax error:") result.stderr.each_line { |l| Chef::Log.fatal(l.chomp) } false end def validate_ruby_file(ruby_file) Chef::Log.debug("Testing #{ruby_file} for syntax errors...") result = shell_out("ruby -c #{ruby_file}") result.error! true rescue Mixlib::ShellOut::ShellCommandFailed file_relative_path = ruby_file[/^#{Regexp.escape(cookbook_path+File::Separator)}(.*)/, 1] Chef::Log.fatal("Cookbook file #{file_relative_path} has a ruby syntax error:") result.stderr.each_line { |l| Chef::Log.fatal(l.chomp) } false end end end end chef-11.8.2/lib/chef/cookbook/file_vendor.rb0000644000004100000410000000320112254362222020636 0ustar www-datawww-data# # Author:: Christopher Walters () # Author:: Tim Hinderliter () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Cookbook # == Chef::Cookbook::FileVendor # This class handles fetching of cookbook files based on specificity. class FileVendor def self.on_create(&block) @instance_creator = block end # Factory method that creates the appropriate kind of # Cookbook::FileVendor to serve the contents of the manifest def self.create_from_manifest(manifest) raise "Must call Chef::Cookbook::FileVendor.on_create before calling create_from_manifest factory" unless defined?(@instance_creator) @instance_creator.call(manifest) end # Gets the on-disk location for the given cookbook file. # # Subclasses are responsible for determining exactly how the # files are obtained and where they are stored. def get_filename(filename) raise NotImplemented, "Subclasses must implement this method" end end end end chef-11.8.2/lib/chef/cookbook/remote_file_vendor.rb0000644000004100000410000000636412254362222022226 0ustar www-datawww-data# # Author:: Tim Hinderliter () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/cookbook/file_vendor' class Chef class Cookbook # == Chef::Cookbook::RemoteFileVendor # This FileVendor loads files by either fetching them from the local cache, or # if not available, loading them from the remote server. class RemoteFileVendor < FileVendor def initialize(manifest, rest) @manifest = manifest @cookbook_name = @manifest[:cookbook_name] @rest = rest end # Implements abstract base's requirement. It looks in the # Chef::Config.cookbook_path file hierarchy for the requested # file. def get_filename(filename) if filename =~ /([^\/]+)\/(.+)$/ segment = $1 else raise "get_filename: Cannot determine segment/filename for incoming filename #{filename}" end raise "No such segment #{segment} in cookbook #{@cookbook_name}" unless @manifest[segment] found_manifest_record = @manifest[segment].find {|manifest_record| manifest_record[:path] == filename } raise "No such file #{filename} in #{@cookbook_name}" unless found_manifest_record cache_filename = File.join("cookbooks", @cookbook_name, found_manifest_record['path']) # update valid_cache_entries so the upstream cache cleaner knows what # we've used. validate_cached_copy(cache_filename) current_checksum = nil if Chef::FileCache.has_key?(cache_filename) current_checksum = Chef::CookbookVersion.checksum_cookbook_file(Chef::FileCache.load(cache_filename, false)) end # If the checksums are different between on-disk (current) and on-server # (remote, per manifest), do the update. This will also execute if there # is no current checksum. if current_checksum != found_manifest_record['checksum'] raw_file = @rest.get_rest(found_manifest_record[:url], true) Chef::Log.debug("Storing updated #{cache_filename} in the cache.") Chef::FileCache.move_to(raw_file.path, cache_filename) else Chef::Log.debug("Not fetching #{cache_filename}, as the cache is up to date.") Chef::Log.debug("current checksum: #{current_checksum}; manifest checksum: #{found_manifest_record['checksum']})") end full_path_cache_filename = Chef::FileCache.load(cache_filename, false) # return the filename, not the contents (second argument= false) full_path_cache_filename end def validate_cached_copy(cache_filename) CookbookCacheCleaner.instance.mark_file_as_valid(cache_filename) end end end end chef-11.8.2/lib/chef/cookbook/cookbook_collection.rb0000644000004100000410000000325612254362222022375 0ustar www-datawww-data#-- # Author:: Tim Hinderliter () # Author:: Christopher Walters () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/mash' class Chef # == Chef::CookbookCollection # This class is the consistent interface for a node to obtain its # cookbooks by name. # # This class is basically a glorified Hash, but since there are # several ways this cookbook information is collected, # (e.g. CookbookLoader for solo, hash of auto-vivified Cookbook # objects for lazily-loaded remote cookbooks), it gets transformed # into this. class CookbookCollection < Mash # The input is a mapping of cookbook name to CookbookVersion objects. We # simply extract them def initialize(cookbook_versions={}) super() do |hash, key| raise Chef::Exceptions::CookbookNotFound, "Cookbook #{key} not found. " << "If you're loading #{key} from another cookbook, make sure you configure the dependency in your metadata" end cookbook_versions.each{ |cookbook_name, cookbook_version| self[cookbook_name] = cookbook_version } end end end chef-11.8.2/lib/chef/cookbook/cookbook_version_loader.rb0000644000004100000410000001406212254362222023252 0ustar www-datawww-data require 'chef/config' require 'chef/cookbook_version' require 'chef/cookbook/chefignore' require 'chef/cookbook/metadata' class Chef class Cookbook class CookbookVersionLoader FILETYPES_SUBJECT_TO_IGNORE = [ :attribute_filenames, :definition_filenames, :recipe_filenames, :template_filenames, :file_filenames, :library_filenames, :resource_filenames, :provider_filenames] attr_reader :cookbook_name attr_reader :cookbook_settings attr_reader :metadata_filenames def initialize(path, chefignore=nil) @cookbook_path = File.expand_path( path ) @cookbook_name = File.basename( path ) @chefignore = chefignore @metadata = Hash.new @relative_path = /#{Regexp.escape(@cookbook_path)}\/(.+)$/ @cookbook_settings = { :attribute_filenames => {}, :definition_filenames => {}, :recipe_filenames => {}, :template_filenames => {}, :file_filenames => {}, :library_filenames => {}, :resource_filenames => {}, :provider_filenames => {}, :root_filenames => {} } @metadata_filenames = [] end def load_cookbooks load_as(:attribute_filenames, 'attributes', '*.rb') load_as(:definition_filenames, 'definitions', '*.rb') load_as(:recipe_filenames, 'recipes', '*.rb') load_as(:library_filenames, 'libraries', '*.rb') load_recursively_as(:template_filenames, "templates", "*") load_recursively_as(:file_filenames, "files", "*") load_recursively_as(:resource_filenames, "resources", "*.rb") load_recursively_as(:provider_filenames, "providers", "*.rb") load_root_files remove_ignored_files if File.exists?(File.join(@cookbook_path, "metadata.rb")) @metadata_filenames << File.join(@cookbook_path, "metadata.rb") elsif File.exists?(File.join(@cookbook_path, "metadata.json")) @metadata_filenames << File.join(@cookbook_path, "metadata.json") end if empty? Chef::Log.warn "found a directory #{cookbook_name} in the cookbook path, but it contains no cookbook files. skipping." end @cookbook_settings end def cookbook_version return nil if empty? Chef::CookbookVersion.new(@cookbook_name.to_sym).tap do |c| c.root_dir = @cookbook_path c.attribute_filenames = cookbook_settings[:attribute_filenames].values c.definition_filenames = cookbook_settings[:definition_filenames].values c.recipe_filenames = cookbook_settings[:recipe_filenames].values c.template_filenames = cookbook_settings[:template_filenames].values c.file_filenames = cookbook_settings[:file_filenames].values c.library_filenames = cookbook_settings[:library_filenames].values c.resource_filenames = cookbook_settings[:resource_filenames].values c.provider_filenames = cookbook_settings[:provider_filenames].values c.root_filenames = cookbook_settings[:root_filenames].values c.metadata_filenames = @metadata_filenames c.metadata = metadata(c) end end # Generates the Cookbook::Metadata object def metadata(cookbook_version) @metadata = Chef::Cookbook::Metadata.new(cookbook_version) @metadata_filenames.each do |metadata_file| case metadata_file when /\.rb$/ apply_ruby_metadata(metadata_file) when /\.json$/ apply_json_metadata(metadata_file) else raise RuntimeError, "Invalid metadata file: #{metadata_file} for cookbook: #{cookbook_version}" end end @metadata end def empty? @cookbook_settings.values.all? { |files_hash| files_hash.empty? } end def merge!(other_cookbook_loader) other_cookbook_settings = other_cookbook_loader.cookbook_settings @cookbook_settings.each do |file_type, file_list| file_list.merge!(other_cookbook_settings[file_type]) end @metadata_filenames.concat(other_cookbook_loader.metadata_filenames) end def chefignore @chefignore ||= Chefignore.new(File.basename(@cookbook_path)) end def load_root_files Dir.glob(File.join(@cookbook_path, '*'), File::FNM_DOTMATCH).each do |file| next if File.directory?(file) @cookbook_settings[:root_filenames][file[@relative_path, 1]] = file end end def load_recursively_as(category, category_dir, glob) file_spec = File.join(@cookbook_path, category_dir, '**', glob) Dir.glob(file_spec, File::FNM_DOTMATCH).each do |file| next if File.directory?(file) @cookbook_settings[category][file[@relative_path, 1]] = file end end def load_as(category, *path_glob) Dir[File.join(@cookbook_path, *path_glob)].each do |file| @cookbook_settings[category][file[@relative_path, 1]] = file end end def remove_ignored_files @cookbook_settings.each_value do |file_list| file_list.reject! do |relative_path, full_path| chefignore.ignored?(relative_path) end end end def apply_ruby_metadata(file) begin @metadata.from_file(file) rescue JSON::ParserError Chef::Log.error("Error evaluating metadata.rb for #@cookbook_name in " + file) raise end end def apply_json_metadata(file) begin @metadata.from_json(IO.read(file)) rescue JSON::ParserError Chef::Log.error("Couldn't parse cookbook metadata JSON for #@cookbook_name in " + file) raise end end end end end chef-11.8.2/lib/chef/search/0000755000004100000410000000000012254362222015460 5ustar www-datawww-datachef-11.8.2/lib/chef/search/query.rb0000644000004100000410000000404512254362222017155 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/config' require 'uri' require 'chef/rest' require 'chef/node' require 'chef/role' require 'chef/data_bag' require 'chef/data_bag_item' class Chef class Search class Query attr_accessor :rest def initialize(url=nil) @rest = Chef::REST.new(url ||Chef::Config[:chef_server_url]) end # Search Solr for objects of a given type, for a given query. If you give # it a block, it will handle the paging for you dynamically. def search(type, query="*:*", sort='X_CHEF_id_CHEF_X asc', start=0, rows=1000, &block) raise ArgumentError, "Type must be a string or a symbol!" unless (type.kind_of?(String) || type.kind_of?(Symbol)) response = @rest.get_rest("search/#{type}?q=#{escape(query)}&sort=#{escape(sort)}&start=#{escape(start)}&rows=#{escape(rows)}") if block response["rows"].each { |o| block.call(o) unless o.nil?} unless (response["start"] + response["rows"].length) >= response["total"] nstart = response["start"] + rows search(type, query, sort, nstart, rows, &block) end true else [ response["rows"], response["start"], response["total"] ] end end def list_indexes @rest.get_rest("search") end private def escape(s) s && URI.escape(s.to_s) end end end end chef-11.8.2/lib/chef/file_content_management/0000755000004100000410000000000012254362222021060 5ustar www-datawww-datachef-11.8.2/lib/chef/file_content_management/deploy/0000755000004100000410000000000012254362222022354 5ustar www-datawww-datachef-11.8.2/lib/chef/file_content_management/deploy/cp.rb0000644000004100000410000000334212254362222023305 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # # # PURPOSE: This strategy preserves the inode, and will preserve modes + ownership # even if the user running chef cannot create that ownership (but has # rights to the file). It is vulnerable to crashes in the middle of # writing the file which could result in corruption or zero-length files. # class Chef class FileContentManagement class Deploy # # PURPOSE: This strategy preserves the inode, and will preserve modes + ownership # even if the user running chef cannot create that ownership (but has # rights to the file). It is vulnerable to crashes in the middle of # writing the file which could result in corruption or zero-length files. # class Cp def create(file) Chef::Log.debug("touching #{file} to create it") FileUtils.touch(file) end def deploy(src, dst) Chef::Log.debug("copying temporary file #{src} into place at #{dst}") FileUtils.cp(src, dst) end end end end end chef-11.8.2/lib/chef/file_content_management/deploy/mv_windows.rb0000644000004100000410000000570512254362222025104 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # # # We update the contents of the file, using mv for atomicity, while maintaining all the # ACL information on the dst file. # require 'chef/platform/query_helpers' if Chef::Platform.windows? require 'chef/win32/security' end class Chef class FileContentManagement class Deploy class MvWindows Security = Chef::ReservedNames::Win32::Security ACL = Security::ACL def create(file) Chef::Log.debug("touching #{file} to create it") FileUtils.touch(file) end def deploy(src, dst) # # At the time of deploy ACLs are correctly configured on the # dst. This would be a simple atomic move operations in # windows was not converting inherited ACLs of src to # non-inherited ACLs in certain cases.See: # http://blogs.msdn.com/b/oldnewthing/archive/2006/08/24/717181.aspx # # # First cache the ACLs of dst file # dst_so = Security::SecurableObject.new(dst) begin # get the sd with the SACL dst_sd = dst_so.security_descriptor(true) rescue Chef::Exceptions::Win32APIError # Catch and raise if the user is not elevated enough. # At this point we can't configure the file as expected so # we're failing action on the resource. raise Chef::Exceptions::WindowsNotAdmin, "can not get the security information for '#{dst}' due to missing Administrator privilages." end if dst_sd.dacl_present? apply_dacl = ACL.create(dst_sd.dacl.select { |ace| !ace.inherited? }) end if dst_sd.sacl_present? apply_sacl = ACL.create(dst_sd.sacl.select { |ace| !ace.inherited? }) end # # Then deploy the file # FileUtils.mv(src, dst) # # Then apply the cached acls to the new dst file # dst_so = Security::SecurableObject.new(dst) dst_so.group = dst_sd.group dst_so.owner = dst_sd.owner dst_so.set_dacl(apply_dacl, dst_sd.dacl_inherits?) if dst_sd.dacl_present? dst_so.set_sacl(apply_sacl, dst_sd.sacl_inherits?) if dst_sd.sacl_present? end end end end end chef-11.8.2/lib/chef/file_content_management/deploy/mv_unix.rb0000644000004100000410000000620112254362222024365 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class FileContentManagement class Deploy # # PURPOSE: this strategy is atomic, and attempts to preserve file modes # # NOTE: there is no preserve flag to FileUtils.mv, and we want to preserve the dst file # modes rather than the src file modes (preserve = true is what mv does already, we # would like preserve = false which is tricky). # class MvUnix def create(file) # this is very simple, but it ensures that ownership and file modes take # good defaults, in particular mode needs to obey umask on create Chef::Log.debug("touching #{file} to create it") FileUtils.touch(file) end def deploy(src, dst) # we are only responsible for content so restore the dst files perms Chef::Log.debug("reading modes from #{dst} file") stat = ::File.stat(dst) mode = stat.mode & 07777 uid = stat.uid gid = stat.gid Chef::Log.debug("applying mode = #{mode.to_s(8)}, uid = #{uid}, gid = #{gid} to #{src}") # i own the inode, so should be able to at least chmod it ::File.chmod(mode, src) # we may be running as non-root in which case because we are doing an mv we cannot preserve # the file modes. after the mv we have a different inode and if we don't have rights to # chown/chgrp on the inode then we can't fix the ownership. # # in the case where i'm running chef-solo on my homedir as myself and some root-shell # work has caused dotfiles of mine to change to root-owned, i'm fine with this not being # exceptional, and i think most use cases will consider this to not be exceptional, and # the right thing is to fix the ownership of the file to the user running the commmand # (which requires write perms to the directory, or mv will throw an exception) begin ::File.chown(uid, nil, src) rescue Errno::EPERM Chef::Log.warn("Could not set uid = #{uid} on #{src}, file modes not preserved") end begin ::File.chown(nil, gid, src) rescue Errno::EPERM Chef::Log.warn("Could not set gid = #{gid} on #{src}, file modes not preserved") end Chef::Log.debug("moving temporary file #{src} into place at #{dst}") FileUtils.mv(src, dst) end end end end end chef-11.8.2/lib/chef/file_content_management/tempfile.rb0000644000004100000410000000340412254362222023213 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require "tempfile" class Chef class FileContentManagement class Tempfile attr_reader :new_resource def initialize(new_resource) @new_resource = new_resource end def tempfile @tempfile ||= tempfile_open end private def tempfile_open tf = ::Tempfile.open(tempfile_basename, tempfile_dirname) # We always process the tempfile in binmode so that we # preserve the line endings of the content. tf.binmode tf end # # These are important for windows to get permissions right, and may # be useful for SELinux and other ACL approaches. Please use them # as the arguments to Tempfile.new() consistently. # def tempfile_basename basename = ::File.basename(@new_resource.name) basename.insert 0, "." unless Chef::Platform.windows? # dotfile if we're not on windows basename end def tempfile_dirname Chef::Config[:file_staging_uses_destdir] ? ::File.dirname(@new_resource.path) : Dir::tmpdir end end end end chef-11.8.2/lib/chef/file_content_management/deploy.rb0000644000004100000410000000217112254362222022702 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/file_content_management/deploy/cp' require 'chef/file_content_management/deploy/mv_unix' if Chef::Platform.windows? require 'chef/file_content_management/deploy/mv_windows' end class Chef class FileContentManagement class Deploy def self.strategy(atomic_update) if atomic_update Chef::Platform.windows? ? MvWindows.new() : MvUnix.new() else Cp.new() end end end end end chef-11.8.2/lib/chef/file_content_management/content_base.rb0000644000004100000410000000314612254362222024055 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class FileContentManagement class ContentBase attr_reader :run_context attr_reader :new_resource attr_reader :current_resource def initialize(new_resource, current_resource, run_context) @new_resource = new_resource @current_resource = current_resource @run_context = run_context @tempfile_loaded = false end def tempfile # tempfile may be nil, so we cannot use ||= here if @tempfile_loaded @tempfile else @tempfile_loaded = true @tempfile = file_for_provider end end private # # Return something that looks like a File or Tempfile and # you must assume the provider will unlink this file. Copy # the contents to a Tempfile if you need to. # def file_for_provider raise "class must implement file_for_provider!" end end end end chef-11.8.2/lib/chef/digester.rb0000644000004100000410000000334512254362222016353 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 Opscode, Inc. # Copyright:: Copyright (c) 2009 Daniel DeLeo # License:: Apache License, Version 2.0 # # 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. # require 'digest' class Chef class Digester def self.instance @instance ||= new end def self.checksum_for_file(*args) instance.checksum_for_file(*args) end def validate_checksum(*args) self.class.validate_checksum(*args) end def checksum_for_file(file) generate_checksum(file) end def generate_checksum(file) checksum_file(file, Digest::SHA256.new) end def self.generate_md5_checksum_for_file(*args) instance.generate_md5_checksum_for_file(*args) end def generate_md5_checksum_for_file(file) checksum_file(file, Digest::MD5.new) end def generate_md5_checksum(io) checksum_io(io, Digest::MD5.new) end private def checksum_file(file, digest) File.open(file, 'rb') { |f| checksum_io(f, digest) } end def checksum_io(io, digest) while chunk = io.read(1024 * 8) digest.update(chunk) end digest.hexdigest end end end chef-11.8.2/lib/chef/provider.rb0000644000004100000410000001240312254362222016372 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Walters () # Copyright:: Copyright (c) 2008, 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/mixin/from_file' require 'chef/mixin/convert_to_class_name' require 'chef/dsl/recipe' require 'chef/mixin/enforce_ownership_and_permissions' require 'chef/mixin/why_run' class Chef class Provider include Chef::DSL::Recipe include Chef::Mixin::WhyRun attr_accessor :new_resource attr_accessor :current_resource attr_accessor :run_context #-- # TODO: this should be a reader, and the action should be passed in the # constructor; however, many/most subclasses override the constructor so # changing the arity would be a breaking change. Change this at the next # break, e.g., Chef 11. attr_accessor :action def initialize(new_resource, run_context) @new_resource = new_resource @action = action @current_resource = nil @run_context = run_context @converge_actions = nil end def whyrun_mode? Chef::Config[:why_run] end def whyrun_supported? false end def node run_context && run_context.node end # Used by providers supporting embedded recipes def resource_collection run_context && run_context.resource_collection end def cookbook_name new_resource.cookbook_name end def load_current_resource raise Chef::Exceptions::Override, "You must override load_current_resource in #{self.to_s}" end def define_resource_requirements end def cleanup_after_converge end def action_nothing Chef::Log.debug("Doing nothing for #{@new_resource.to_s}") true end def events run_context.events end def run_action(action=nil) @action = action unless action.nil? # TODO: it would be preferable to get the action to be executed in the # constructor... # user-defined LWRPs may include unsafe load_current_resource methods that cannot be run in whyrun mode if !whyrun_mode? || whyrun_supported? load_current_resource events.resource_current_state_loaded(@new_resource, @action, @current_resource) elsif whyrun_mode? && !whyrun_supported? events.resource_current_state_load_bypassed(@new_resource, @action, @current_resource) end define_resource_requirements process_resource_requirements # user-defined providers including LWRPs may # not include whyrun support - if they don't support it # we can't execute any actions while we're running in # whyrun mode. Instead we 'fake' whyrun by documenting that # we can't execute the action. # in non-whyrun mode, this will still cause the action to be # executed normally. if whyrun_supported? && !requirements.action_blocked?(@action) send("action_#{@action}") elsif whyrun_mode? events.resource_bypassed(@new_resource, @action, self) else send("action_#{@action}") end set_updated_status cleanup_after_converge end def process_resource_requirements requirements.run(:all_actions) unless @action == :nothing requirements.run(@action) end def resource_updated? !converge_actions.empty? || @new_resource.updated_by_last_action? end def set_updated_status if !resource_updated? events.resource_up_to_date(@new_resource, @action) else events.resource_updated(@new_resource, @action) new_resource.updated_by_last_action(true) end end def requirements @requirements ||= ResourceRequirements.new(@new_resource, run_context) end def converge_by(descriptions, &block) converge_actions.add_action(descriptions, &block) end protected def converge_actions @converge_actions ||= ConvergeActions.new(@new_resource, run_context, @action) end def recipe_eval(&block) # This block has new resource definitions within it, which # essentially makes it an in-line Chef run. Save our current # run_context and create one anew, so the new Chef run only # executes the embedded resources. # # TODO: timh,cw: 2010-5-14: This means that the resources within # this block cannot interact with resources outside, e.g., # manipulating notifies. converge_by ("evaluate block and run any associated actions") do saved_run_context = @run_context @run_context = @run_context.dup @run_context.resource_collection = Chef::ResourceCollection.new instance_eval(&block) Chef::Runner.new(@run_context).converge @run_context = saved_run_context end end end end chef-11.8.2/lib/chef/client.rb0000644000004100000410000005045412254362222016026 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Walters () # Author:: Christopher Brown () # Author:: Tim Hinderliter () # Copyright:: Copyright (c) 2008-2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'chef/config' require 'chef/mixin/params_validate' require 'chef/mixin/path_sanity' require 'chef/log' require 'chef/rest' require 'chef/api_client' require 'chef/api_client/registration' require 'chef/platform/query_helpers' require 'chef/node' require 'chef/role' require 'chef/file_cache' require 'chef/run_context' require 'chef/runner' require 'chef/run_status' require 'chef/cookbook/cookbook_collection' require 'chef/cookbook/file_vendor' require 'chef/cookbook/file_system_file_vendor' require 'chef/cookbook/remote_file_vendor' require 'chef/event_dispatch/dispatcher' require 'chef/formatters/base' require 'chef/formatters/doc' require 'chef/formatters/minimal' require 'chef/version' require 'chef/resource_reporter' require 'chef/run_lock' require 'ohai' require 'rbconfig' class Chef # == Chef::Client # The main object in a Chef run. Preps a Chef::Node and Chef::RunContext, # syncs cookbooks if necessary, and triggers convergence. class Client include Chef::Mixin::PathSanity # Clears all notifications for client run status events. # Primarily for testing purposes. def self.clear_notifications @run_start_notifications = nil @run_completed_successfully_notifications = nil @run_failed_notifications = nil end # The list of notifications to be run when the client run starts. def self.run_start_notifications @run_start_notifications ||= [] end # The list of notifications to be run when the client run completes # successfully. def self.run_completed_successfully_notifications @run_completed_successfully_notifications ||= [] end # The list of notifications to be run when the client run fails. def self.run_failed_notifications @run_failed_notifications ||= [] end # Add a notification for the 'client run started' event. The notification # is provided as a block. The current Chef::RunStatus object will be passed # to the notification_block when the event is triggered. def self.when_run_starts(¬ification_block) run_start_notifications << notification_block end # Add a notification for the 'client run success' event. The notification # is provided as a block. The current Chef::RunStatus object will be passed # to the notification_block when the event is triggered. def self.when_run_completes_successfully(¬ification_block) run_completed_successfully_notifications << notification_block end # Add a notification for the 'client run failed' event. The notification # is provided as a block. The current Chef::RunStatus is passed to the # notification_block when the event is triggered. def self.when_run_fails(¬ification_block) run_failed_notifications << notification_block end # Callback to fire notifications that the Chef run is starting def run_started self.class.run_start_notifications.each do |notification| notification.call(run_status) end @events.run_started(run_status) end # Callback to fire notifications that the run completed successfully def run_completed_successfully success_handlers = self.class.run_completed_successfully_notifications success_handlers.each do |notification| notification.call(run_status) end end # Callback to fire notifications that the Chef run failed def run_failed failure_handlers = self.class.run_failed_notifications failure_handlers.each do |notification| notification.call(run_status) end end attr_accessor :node attr_accessor :ohai attr_accessor :rest attr_accessor :runner #-- # TODO: timh/cw: 5-19-2010: json_attribs should be moved to RunContext? attr_reader :json_attribs attr_reader :run_status attr_reader :events # Creates a new Chef::Client. def initialize(json_attribs=nil, args={}) @json_attribs = json_attribs @node = nil @run_status = nil @runner = nil @ohai = Ohai::System.new event_handlers = configure_formatters event_handlers += Array(Chef::Config[:event_handlers]) @events = EventDispatch::Dispatcher.new(*event_handlers) @override_runlist = args.delete(:override_runlist) runlist_override_sanity_check! end def configure_formatters formatters_for_run.map do |formatter_name, output_path| if output_path.nil? Chef::Formatters.new(formatter_name, STDOUT, STDERR) else io = File.open(output_path, "a+") io.sync = true Chef::Formatters.new(formatter_name, io, io) end end end def formatters_for_run if Chef::Config.formatters.empty? [default_formatter] else Chef::Config.formatters end end def default_formatter if (STDOUT.tty? && !Chef::Config[:force_logger]) || Chef::Config[:force_formatter] [:doc] else [:null] end end # Do a full run for this Chef::Client. Calls: # * do_run # # This provides a wrapper around #do_run allowing the # run to be optionally forked. # === Returns # boolean:: Return value from #do_run. Should always returns true. def run # win32-process gem exposes some form of :fork for Process # class. So we are seperately ensuring that the platform we're # running on is not windows before forking. if(Chef::Config[:client_fork] && Process.respond_to?(:fork) && !Chef::Platform.windows?) Chef::Log.info "Forking chef instance to converge..." pid = fork do [:INT, :TERM].each {|s| trap(s, "EXIT") } client_solo = Chef::Config[:solo] ? "chef-solo" : "chef-client" $0 = "#{client_solo} worker: ppid=#{Process.ppid};start=#{Time.new.strftime("%R:%S")};" begin Chef::Log.debug "Forked instance now converging" do_run rescue Exception => e Chef::Log.error(e.to_s) exit 1 else exit 0 end end Chef::Log.debug "Fork successful. Waiting for new chef pid: #{pid}" result = Process.waitpid2(pid) handle_child_exit(result) Chef::Log.debug "Forked instance successfully reaped (pid: #{pid})" true else do_run end end def handle_child_exit(pid_and_status) status = pid_and_status[1] return true if status.success? message = if status.signaled? "Chef run process terminated by signal #{status.termsig} (#{Signal.list.invert[status.termsig]})" else "Chef run process exited unsuccessfully (exit code #{status.exitstatus})" end raise Exceptions::ChildConvergeError, message end # Configures the Chef::Cookbook::FileVendor class to fetch file from the # server or disk as appropriate, creates the run context for this run, and # sanity checks the cookbook collection. #===Returns # Chef::RunContext:: the run context for this run. def setup_run_context if Chef::Config[:solo] Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, Chef::Config[:cookbook_path]) } cl = Chef::CookbookLoader.new(Chef::Config[:cookbook_path]) cl.load_cookbooks cookbook_collection = Chef::CookbookCollection.new(cl) run_context = Chef::RunContext.new(node, cookbook_collection, @events) else Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::RemoteFileVendor.new(manifest, rest) } cookbook_hash = sync_cookbooks cookbook_collection = Chef::CookbookCollection.new(cookbook_hash) run_context = Chef::RunContext.new(node, cookbook_collection, @events) end run_status.run_context = run_context run_context.load(@run_list_expansion) assert_cookbook_path_not_empty(run_context) run_context end def save_updated_node unless Chef::Config[:solo] Chef::Log.debug("Saving the current state of node #{node_name}") if(@original_runlist) @node.run_list(*@original_runlist) @node.automatic_attrs[:runlist_override_history] = {Time.now.to_i => @override_runlist.inspect} end @node.save end end def run_ohai ohai.all_plugins end def node_name name = Chef::Config[:node_name] || ohai[:fqdn] || ohai[:hostname] Chef::Config[:node_name] = name unless name msg = "Unable to determine node name: configure node_name or configure the system's hostname and fqdn" raise Chef::Exceptions::CannotDetermineNodeName, msg end # node names > 90 bytes only work with authentication protocol >= 1.1 # see discussion in config.rb. if name.bytesize > 90 Chef::Config[:authentication_protocol_version] = "1.1" end name end # Applies environment, external JSON attributes, and override run list to # the node, Then expands the run_list. # # === Returns # node:: The modified @node object. @node is modified in place. def build_node # Allow user to override the environment of a node by specifying # a config parameter. if Chef::Config[:environment] && !Chef::Config[:environment].chop.empty? @node.chef_environment(Chef::Config[:environment]) end # consume_external_attrs may add items to the run_list. Save the # expanded run_list, which we will pass to the server later to # determine which versions of cookbooks to use. @node.reset_defaults_and_overrides @node.consume_external_attrs(ohai.data, @json_attribs) unless(@override_runlist.empty?) @original_runlist = @node.run_list.run_list_items.dup runlist_override_sanity_check! @node.run_list(*@override_runlist) Chef::Log.warn "Run List override has been provided." Chef::Log.warn "Original Run List: [#{@original_runlist.join(', ')}]" Chef::Log.warn "Overridden Run List: [#{@node.run_list}]" end @run_list_expansion = expand_run_list # @run_list_expansion is a RunListExpansion. # # Convert @expanded_run_list, which is an # Array of Hashes of the form # {:name => NAME, :version_constraint => Chef::VersionConstraint }, # into @expanded_run_list_with_versions, an # Array of Strings of the form # "#{NAME}@#{VERSION}" @expanded_run_list_with_versions = @run_list_expansion.recipes.with_version_constraints_strings Chef::Log.info("Run List is [#{@node.run_list}]") Chef::Log.info("Run List expands to [#{@expanded_run_list_with_versions.join(', ')}]") @run_status = Chef::RunStatus.new(@node, @events) @events.node_load_completed(node, @expanded_run_list_with_versions, Chef::Config) @node end # In client-server operation, loads the node state from the server. In # chef-solo operation, builds a new node object. def load_node @events.node_load_start(node_name, Chef::Config) Chef::Log.debug("Building node object for #{node_name}") if Chef::Config[:solo] @node = Chef::Node.build(node_name) else @node = Chef::Node.find_or_create(node_name) end rescue Exception => e # TODO: wrap this exception so useful error info can be given to the # user. @events.node_load_failed(node_name, e, Chef::Config) raise end def expand_run_list if Chef::Config[:solo] @node.expand!('disk') else @node.expand!('server') end rescue Exception => e # TODO: wrap/munge exception with useful error output. @events.run_list_expand_failed(node, e) raise end # # === Returns # rest:: returns Chef::REST connection object def register(client_name=node_name, config=Chef::Config) if !config[:client_key] @events.skipping_registration(client_name, config) Chef::Log.debug("Client key is unspecified - skipping registration") elsif File.exists?(config[:client_key]) @events.skipping_registration(client_name, config) Chef::Log.debug("Client key #{config[:client_key]} is present - skipping registration") else @events.registration_start(node_name, config) Chef::Log.info("Client key #{config[:client_key]} is not present - registering") Chef::ApiClient::Registration.new(node_name, config[:client_key]).run @events.registration_completed end # We now have the client key, and should use it from now on. @rest = Chef::REST.new(config[:chef_server_url], client_name, config[:client_key]) @resource_reporter = Chef::ResourceReporter.new(@rest) @events.register(@resource_reporter) rescue Exception => e # TODO: munge exception so a semantic failure message can be given to the # user @events.registration_failed(node_name, e, config) raise end # Sync_cookbooks eagerly loads all files except files and # templates. It returns the cookbook_hash -- the return result # from /environments/#{node.chef_environment}/cookbook_versions, # which we will use for our run_context. # # === Returns # Hash:: The hash of cookbooks with download URLs as given by the server def sync_cookbooks Chef::Log.debug("Synchronizing cookbooks") begin @events.cookbook_resolution_start(@expanded_run_list_with_versions) cookbook_hash = rest.post_rest("environments/#{@node.chef_environment}/cookbook_versions", {:run_list => @expanded_run_list_with_versions}) rescue Exception => e # TODO: wrap/munge exception to provide helpful error output @events.cookbook_resolution_failed(@expanded_run_list_with_versions, e) raise else @events.cookbook_resolution_complete(cookbook_hash) end synchronizer = Chef::CookbookSynchronizer.new(cookbook_hash, @events) synchronizer.sync_cookbooks # register the file cache path in the cookbook path so that CookbookLoader actually picks up the synced cookbooks Chef::Config[:cookbook_path] = File.join(Chef::Config[:file_cache_path], "cookbooks") cookbook_hash end # Converges the node. # # === Returns # true:: Always returns true def converge(run_context) @events.converge_start(run_context) Chef::Log.debug("Converging node #{node_name}") @runner = Chef::Runner.new(run_context) runner.converge @events.converge_complete true rescue Exception # TODO: should this be a separate #converge_failed(exception) method? @events.converge_complete raise end def do_windows_admin_check if Chef::Platform.windows? Chef::Log.debug("Checking for administrator privileges....") if !has_admin_privileges? message = "chef-client doesn't have administrator privileges on node #{node_name}." if Chef::Config[:fatal_windows_admin_check] Chef::Log.fatal(message) Chef::Log.fatal("fatal_windows_admin_check is set to TRUE.") raise Chef::Exceptions::WindowsNotAdmin, message else Chef::Log.warn("#{message} This might cause unexpected resource failures.") end else Chef::Log.debug("chef-client has administrator privileges on node #{node_name}.") end end end private # Do a full run for this Chef::Client. Calls: # # * run_ohai - Collect information about the system # * build_node - Get the last known state, merge with local changes # * register - If not in solo mode, make sure the server knows about this client # * sync_cookbooks - If not in solo mode, populate the local cache with the node's cookbooks # * converge - Bring this system up to date # # === Returns # true:: Always returns true. def do_run runlock = RunLock.new(Chef::Config.lockfile) runlock.acquire # don't add code that may fail before entering this section to be sure to release lock begin runlock.save_pid run_context = nil @events.run_start(Chef::VERSION) Chef::Log.info("*** Chef #{Chef::VERSION} ***") Chef::Log.info "Chef-client pid: #{Process.pid}" enforce_path_sanity run_ohai @events.ohai_completed(node) register unless Chef::Config[:solo] load_node build_node run_status.start_clock Chef::Log.info("Starting Chef Run for #{node.name}") run_started do_windows_admin_check run_context = setup_run_context converge(run_context) save_updated_node run_status.stop_clock Chef::Log.info("Chef Run complete in #{run_status.elapsed_time} seconds") run_completed_successfully @events.run_completed(node) true rescue Exception => e # CHEF-3336: Send the error first in case something goes wrong below and we don't know why Chef::Log.debug("Re-raising exception: #{e.class} - #{e.message}\n#{e.backtrace.join("\n ")}") # If we failed really early, we may not have a run_status yet. Too early for these to be of much use. if run_status run_status.stop_clock run_status.exception = e run_failed end Chef::Application.debug_stacktrace(e) @events.run_failed(e) raise ensure @run_status = nil run_context = nil runlock.release GC.start end true end # Ensures runlist override contains RunListItem instances def runlist_override_sanity_check! # Convert to array and remove whitespace if @override_runlist.is_a?(String) @override_runlist = @override_runlist.split(',').map { |e| e.strip } end @override_runlist = [@override_runlist].flatten.compact @override_runlist.map! do |item| if(item.is_a?(Chef::RunList::RunListItem)) item else Chef::RunList::RunListItem.new(item) end end end def directory_not_empty?(path) File.exists?(path) && (Dir.entries(path).size > 2) end def is_last_element?(index, object) object.kind_of?(Array) ? index == object.size - 1 : true end def assert_cookbook_path_not_empty(run_context) if Chef::Config[:solo] # Check for cookbooks in the path given # Chef::Config[:cookbook_path] can be a string or an array # if it's an array, go through it and check each one, raise error at the last one if no files are found Chef::Log.debug "Loading from cookbook_path: #{Array(Chef::Config[:cookbook_path]).map { |path| File.expand_path(path) }.join(', ')}" Array(Chef::Config[:cookbook_path]).each_with_index do |cookbook_path, index| if directory_not_empty?(cookbook_path) break else msg = "No cookbook found in #{Chef::Config[:cookbook_path].inspect}, make sure cookbook_path is set correctly." Chef::Log.fatal(msg) raise Chef::Exceptions::CookbookNotFound, msg if is_last_element?(index, Chef::Config[:cookbook_path]) end end else Chef::Log.warn("Node #{node_name} has an empty run list.") if run_context.node.run_list.empty? end end def has_admin_privileges? require 'chef/win32/security' Chef::ReservedNames::Win32::Security.has_admin_privileges? end end end # HACK cannot load this first, but it must be loaded. require 'chef/cookbook_loader' require 'chef/cookbook_version' require 'chef/cookbook/synchronizer' chef-11.8.2/lib/chef/resource_reporter.rb0000644000004100000410000002460312254362222020316 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Author:: Prajakta Purohit (prajakta@opscode.com>) # Auther:: Tyler Cloke () # # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'uri' require 'chef/monkey_patches/securerandom' require 'chef/event_dispatch/base' class Chef class ResourceReporter < EventDispatch::Base class ResourceReport < Struct.new(:new_resource, :current_resource, :action, :exception, :elapsed_time) def self.new_with_current_state(new_resource, action, current_resource) report = new report.new_resource = new_resource report.action = action report.current_resource = current_resource report end def self.new_for_exception(new_resource, action) report = new report.new_resource = new_resource report.action = action report end def for_json as_hash = {} as_hash["type"] = new_resource.class.dsl_name as_hash["name"] = new_resource.name as_hash["id"] = new_resource.identity as_hash["after"] = state(new_resource) as_hash["before"] = current_resource ? state(current_resource) : {} as_hash["duration"] = (elapsed_time * 1000).to_i.to_s as_hash["delta"] = new_resource.diff if new_resource.respond_to?("diff") as_hash["delta"] = "" if as_hash["delta"].nil? # TODO: rename as "action" as_hash["result"] = action.to_s if success? else #as_hash["result"] = "failed" end if new_resource.cookbook_name as_hash["cookbook_name"] = new_resource.cookbook_name as_hash["cookbook_version"] = new_resource.cookbook_version.version end as_hash end def finish self.elapsed_time = new_resource.elapsed_time end def success? !self.exception end def state(r) r.class.state_attrs.inject({}) do |state_attrs, attr_name| state_attrs[attr_name] = r.send(attr_name) state_attrs end end end # End class ResouceReport attr_reader :updated_resources attr_reader :status attr_reader :exception attr_reader :run_id attr_reader :error_descriptions PROTOCOL_VERSION = '0.1.0' def initialize(rest_client) if Chef::Config[:enable_reporting] && !Chef::Config[:why_run] @reporting_enabled = true else @reporting_enabled = false end @updated_resources = [] @total_res_count = 0 @pending_update = nil @status = "success" @exception = nil @run_id = SecureRandom.uuid @rest_client = rest_client @error_descriptions = {} end def run_started(run_status) @run_status = run_status if reporting_enabled? begin resource_history_url = "reports/nodes/#{node_name}/runs" server_response = @rest_client.post_rest(resource_history_url, {:action => :start, :run_id => @run_id, :start_time => start_time.to_s}, headers) rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError => e handle_error_starting_run(e, resource_history_url) end end end def handle_error_starting_run(e, url) message = "Reporting error starting run. URL: #{url} " code = if e.response.code e.response.code.to_s else "Exception Code Empty" end if !e.response || (code != "404" && code != "406") exception = "Exception: #{code} " if Chef::Config[:enable_reporting_url_fatals] reporting_status = "Reporting fatals enabled. Aborting run. " Chef::Log.error(message + exception + reporting_status) raise else reporting_status = "Disabling reporting for run." Chef::Log.info(message + exception + reporting_status) end else reason = "Received #{code}. " if code == "406" reporting_status = "Client version not supported. Please update the client. Disabling reporting for run." Chef::Log.info(message + reason + reporting_status) else reporting_status = "Disabling reporting for run." Chef::Log.debug(message + reason + reporting_status) end end @reporting_enabled = false end def resource_current_state_loaded(new_resource, action, current_resource) unless nested_resource?(new_resource) @pending_update = ResourceReport.new_with_current_state(new_resource, action, current_resource) end end def resource_up_to_date(new_resource, action) @total_res_count += 1 @pending_update = nil unless nested_resource?(new_resource) end def resource_skipped(resource, action, conditional) @total_res_count += 1 @pending_update = nil unless nested_resource?(resource) end def resource_updated(new_resource, action) @total_res_count += 1 end def resource_failed(new_resource, action, exception) @total_res_count += 1 unless nested_resource?(new_resource) @pending_update ||= ResourceReport.new_for_exception(new_resource, action) @pending_update.exception = exception end description = Formatters::ErrorMapper.resource_failed(new_resource, action, exception) @error_descriptions = description.for_json end def resource_completed(new_resource) if @pending_update && !nested_resource?(new_resource) @pending_update.finish @updated_resources << @pending_update @pending_update = nil end end def run_completed(node) @status = "success" post_reporting_data end def run_failed(exception) @exception = exception @status = "failure" # If we failed before we received the run_started callback, there's not much we can do # in terms of reporting if @run_status post_reporting_data end end def post_reporting_data if reporting_enabled? run_data = prepare_run_data resource_history_url = "reports/nodes/#{node_name}/runs/#{@run_id}" Chef::Log.info("Sending resource update report (run-id: #{@run_id})") Chef::Log.debug run_data.inspect compressed_data = encode_gzip(run_data.to_json) begin Chef::Log.debug("Sending compressed run data...") # Since we're posting compressed data we can not directly call post_rest which expects JSON reporting_url = @rest_client.create_url(resource_history_url) @rest_client.raw_http_request(:POST, reporting_url, headers({'Content-Encoding' => 'gzip'}), compressed_data) rescue Net::HTTPServerException => e if e.response.code.to_s == "400" Chef::FileCache.store("failed-reporting-data.json", Chef::JSONCompat.to_json_pretty(run_data), 0640) Chef::Log.error("Failed to post reporting data to server (HTTP 400), saving to #{Chef::FileCache.load("failed-reporting-data.json", false)}") else Chef::Log.error("Failed to post reporting data to server (HTTP #{e.response.code.to_s})") end end else Chef::Log.debug("Server doesn't support resource history, skipping resource report.") end end def headers(additional_headers = {}) options = {'X-Ops-Reporting-Protocol-Version' => PROTOCOL_VERSION} options.merge(additional_headers) end def node_name @run_status.node.name end def start_time @run_status.start_time end def end_time @run_status.end_time end def prepare_run_data run_data = {} run_data["action"] = "end" run_data["resources"] = updated_resources.map do |resource_record| resource_record.for_json end run_data["status"] = @status run_data["run_list"] = @run_status.node.run_list.to_json run_data["total_res_count"] = @total_res_count.to_s run_data["data"] = {} run_data["start_time"] = start_time.to_s run_data["end_time"] = end_time.to_s if exception exception_data = {} exception_data["class"] = exception.inspect exception_data["message"] = exception.message exception_data["backtrace"] = exception.backtrace.to_json exception_data["description"] = @error_descriptions run_data["data"]["exception"] = exception_data end run_data end def run_list_expand_failed(node, exception) description = Formatters::ErrorMapper.run_list_expand_failed(node, exception) @error_descriptions = description.for_json end def cookbook_resolution_failed(expanded_run_list, exception) description = Formatters::ErrorMapper.cookbook_resolution_failed(expanded_run_list, exception) @error_descriptions = description.for_json end def cookbook_sync_failed(cookbooks, exception) description = Formatters::ErrorMapper.cookbook_sync_failed(cookbooks, exception) @error_descriptions = description.for_json end def reporting_enabled? @reporting_enabled end private # If we are getting messages about a resource while we are in the middle of # another resource's update, we assume that the nested resource is just the # implementation of a provider, and we want to hide it from the reporting # output. def nested_resource?(new_resource) @pending_update && @pending_update.new_resource != new_resource end def encode_gzip(data) "".tap do |out| Zlib::GzipWriter.wrap(StringIO.new(out)){|gz| gz << data } end end end end chef-11.8.2/lib/chef/encrypted_data_bag_item.rb0000644000004100000410000003233012254362222021356 0ustar www-datawww-data# # Author:: Seth Falcon () # Copyright:: Copyright 2010-2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'base64' require 'openssl' require 'chef/data_bag_item' require 'yaml' require 'yajl' require 'open-uri' # An EncryptedDataBagItem represents a read-only data bag item where # all values, except for the value associated with the id key, have # been encrypted. # # EncrypedDataBagItem can be used in recipes to decrypt data bag item # members. # # Data bag item values are assumed to have been encrypted using the # default symmetric encryption provided by Encryptor.encrypt where # values are converted to YAML prior to encryption. # # If the shared secret is not specified at initialization or load, # then the contents of the file referred to in # Chef::Config[:encrypted_data_bag_secret] will be used as the # secret. The default path is /etc/chef/encrypted_data_bag_secret # # EncryptedDataBagItem is intended to provide a means to avoid storing # data bag items in the clear on the Chef server. This provides some # protection against a breach of the Chef server or of Chef server # backup data. Because the secret must be stored in the clear on any # node needing access to an EncryptedDataBagItem, this approach # provides no protection of data bag items from actors with access to # such nodes in the infrastructure. # class Chef::EncryptedDataBagItem ALGORITHM = 'aes-256-cbc' class UnacceptableEncryptedDataBagItemFormat < StandardError end class UnsupportedEncryptedDataBagItemFormat < StandardError end class DecryptionFailure < StandardError end class UnsupportedCipher < StandardError end # Implementation class for converting plaintext data bag item values to an # encrypted value, including any necessary wrappers and metadata. module Encryptor # "factory" method that creates an encryptor object with the proper class # for the desired encrypted data bag format version. # # +Chef::Config[:data_bag_encrypt_version]+ determines which version is used. def self.new(value, secret, iv=nil) format_version = Chef::Config[:data_bag_encrypt_version] case format_version when 1 Version1Encryptor.new(value, secret, iv) when 2 Version2Encryptor.new(value, secret, iv) else raise UnsupportedEncryptedDataBagItemFormat, "Invalid encrypted data bag format version `#{format_version}'. Supported versions are '1', '2'" end end class Version1Encryptor attr_reader :key attr_reader :plaintext_data # Create a new Encryptor for +data+, which will be encrypted with the given # +key+. # # === Arguments: # * data: An object of any type that can be serialized to json # * key: A String representing the desired passphrase # * iv: The optional +iv+ parameter is intended for testing use only. When # *not* supplied, Encryptor will use OpenSSL to generate a secure random # IV, which is what you want. def initialize(plaintext_data, key, iv=nil) @plaintext_data = plaintext_data @key = key @iv = iv && Base64.decode64(iv) end # Returns a wrapped and encrypted version of +plaintext_data+ suitable for # using as the value in an encrypted data bag item. def for_encrypted_item { "encrypted_data" => encrypted_data, "iv" => Base64.encode64(iv), "version" => 1, "cipher" => ALGORITHM } end # Generates or returns the IV. def iv # Generated IV comes from OpenSSL::Cipher::Cipher#random_iv # This gets generated when +openssl_encryptor+ gets created. openssl_encryptor if @iv.nil? @iv end # Generates (and memoizes) an OpenSSL::Cipher::Cipher object and configures # it for the specified iv and encryption key. def openssl_encryptor @openssl_encryptor ||= begin encryptor = OpenSSL::Cipher::Cipher.new(ALGORITHM) encryptor.encrypt @iv ||= encryptor.random_iv encryptor.iv = @iv encryptor.key = Digest::SHA256.digest(key) encryptor end end # Encrypts and Base64 encodes +serialized_data+ def encrypted_data @encrypted_data ||= begin enc_data = openssl_encryptor.update(serialized_data) enc_data << openssl_encryptor.final Base64.encode64(enc_data) end end # Wraps the data in a single key Hash (JSON Object) and converts to JSON. # The wrapper is required because we accept values (such as Integers or # Strings) that do not produce valid JSON when serialized without the # wrapper. def serialized_data Yajl::Encoder.encode(:json_wrapper => plaintext_data) end end class Version2Encryptor < Version1Encryptor # Returns a wrapped and encrypted version of +plaintext_data+ suitable for # using as the value in an encrypted data bag item. def for_encrypted_item { "encrypted_data" => encrypted_data, "hmac" => hmac, "iv" => Base64.encode64(iv), "version" => 2, "cipher" => ALGORITHM } end # Generates an HMAC-SHA2-256 of the encrypted data (encrypt-then-mac) def hmac @hmac ||= begin digest = OpenSSL::Digest::Digest.new("sha256") raw_hmac = OpenSSL::HMAC.digest(digest, key, encrypted_data) Base64.encode64(raw_hmac) end end end end #=== Decryptor # For backwards compatibility, Chef implements decryption/deserialization for # older encrypted data bag item formats in addition to the current version. # Each decryption/deserialization strategy is implemented as a class in this # namespace. For convenience the factory method +Decryptor.for()+ can be used # to create an instance of the appropriate strategy for the given encrypted # data bag value. module Decryptor # Detects the encrypted data bag item format version and instantiates a # decryptor object for that version. Call #for_decrypted_item on the # resulting object to decrypt and deserialize it. def self.for(encrypted_value, key) format_version = format_version_of(encrypted_value) assert_format_version_acceptable!(format_version) case format_version when 2 Version2Decryptor.new(encrypted_value, key) when 1 Version1Decryptor.new(encrypted_value, key) when 0 Version0Decryptor.new(encrypted_value, key) else raise UnsupportedEncryptedDataBagItemFormat, "This version of chef does not support encrypted data bag item format version '#{format_version}'" end end def self.format_version_of(encrypted_value) if encrypted_value.respond_to?(:key?) encrypted_value["version"] else 0 end end def self.assert_format_version_acceptable!(format_version) unless format_version.kind_of?(Integer) and format_version >= Chef::Config[:data_bag_decrypt_minimum_version] raise UnacceptableEncryptedDataBagItemFormat, "The encrypted data bag item has format version `#{format_version}', " + "but the config setting 'data_bag_decrypt_minimum_version' requires version `#{Chef::Config[:data_bag_decrypt_minimum_version]}'" end end class Version1Decryptor attr_reader :encrypted_data attr_reader :key def initialize(encrypted_data, key) @encrypted_data = encrypted_data @key = key end def for_decrypted_item Yajl::Parser.parse(decrypted_data)["json_wrapper"] rescue Yajl::ParseError # convert to a DecryptionFailure error because the most likely scenario # here is that the decryption step was unsuccessful but returned bad # data rather than raising an error. raise DecryptionFailure, "Error decrypting data bag value. Most likely the provided key is incorrect" end def encrypted_bytes Base64.decode64(@encrypted_data["encrypted_data"]) end def iv Base64.decode64(@encrypted_data["iv"]) end def decrypted_data @decrypted_data ||= begin plaintext = openssl_decryptor.update(encrypted_bytes) plaintext << openssl_decryptor.final rescue OpenSSL::Cipher::CipherError => e raise DecryptionFailure, "Error decrypting data bag value: '#{e.message}'. Most likely the provided key is incorrect" end end def openssl_decryptor @openssl_decryptor ||= begin assert_valid_cipher! d = OpenSSL::Cipher::Cipher.new(ALGORITHM) d.decrypt d.key = Digest::SHA256.digest(key) d.iv = iv d end end def assert_valid_cipher! # In the future, chef may support configurable ciphers. For now, only # aes-256-cbc is supported. requested_cipher = @encrypted_data["cipher"] unless requested_cipher == ALGORITHM raise UnsupportedCipher, "Cipher '#{requested_cipher}' is not supported by this version of Chef. Available ciphers: ['#{ALGORITHM}']" end end end class Version2Decryptor < Version1Decryptor def decrypted_data validate_hmac! unless @decrypted_data super end def validate_hmac! digest = OpenSSL::Digest::Digest.new("sha256") raw_hmac = OpenSSL::HMAC.digest(digest, key, @encrypted_data["encrypted_data"]) if candidate_hmac_matches?(raw_hmac) true else raise DecryptionFailure, "Error decrypting data bag value: invalid hmac. Most likely the provided key is incorrect" end end private def candidate_hmac_matches?(expected_hmac) return false unless @encrypted_data["hmac"] expected_bytes = expected_hmac.bytes.to_a candidate_hmac_bytes = Base64.decode64(@encrypted_data["hmac"]).bytes.to_a valid = expected_bytes.size ^ candidate_hmac_bytes.size expected_bytes.zip(candidate_hmac_bytes) { |x, y| valid |= x ^ y.to_i } valid == 0 end end class Version0Decryptor attr_reader :encrypted_data attr_reader :key def initialize(encrypted_data, key) @encrypted_data = encrypted_data @key = key end def for_decrypted_item YAML.load(decrypted_data) end def decrypted_data @decrypted_data ||= begin plaintext = openssl_decryptor.update(encrypted_bytes) plaintext << openssl_decryptor.final rescue OpenSSL::Cipher::CipherError => e raise DecryptionFailure, "Error decrypting data bag value: '#{e.message}'. Most likely the provided key is incorrect" end end def encrypted_bytes Base64.decode64(@encrypted_data) end def openssl_decryptor @openssl_decryptor ||= begin d = OpenSSL::Cipher::Cipher.new(ALGORITHM) d.decrypt d.pkcs5_keyivgen(key) d end end end end def initialize(enc_hash, secret) @enc_hash = enc_hash @secret = secret end def [](key) value = @enc_hash[key] if key == "id" || value.nil? value else Decryptor.for(value, @secret).for_decrypted_item end end def []=(key, value) raise ArgumentError, "assignment not supported for #{self.class}" end def to_hash @enc_hash.keys.inject({}) { |hash, key| hash[key] = self[key]; hash } end def self.encrypt_data_bag_item(plain_hash, secret) plain_hash.inject({}) do |h, (key, val)| h[key] = if key != "id" Encryptor.new(val, secret).for_encrypted_item else val end h end end def self.load(data_bag, name, secret = nil) raw_hash = Chef::DataBagItem.load(data_bag, name) secret = secret || self.load_secret self.new(raw_hash, secret) end def self.load_secret(path=nil) path ||= Chef::Config[:encrypted_data_bag_secret] secret = case path when /^\w+:\/\// # We have a remote key begin Kernel.open(path).read.strip rescue Errno::ECONNREFUSED raise ArgumentError, "Remote key not available from '#{path}'" rescue OpenURI::HTTPError raise ArgumentError, "Remote key not found at '#{path}'" end else if !File.exist?(path) raise Errno::ENOENT, "file not found '#{path}'" end IO.read(path).strip end if secret.size < 1 raise ArgumentError, "invalid zero length secret in '#{path}'" end secret end end chef-11.8.2/lib/chef/resource_collection.rb0000644000004100000410000001714012254362222020605 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Walters () # Copyright:: Copyright (c) 2008, 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource' require 'chef/resource_collection/stepable_iterator' class Chef class ResourceCollection include Enumerable # Matches a multiple resource lookup specification, # e.g., "service[nginx,unicorn]" MULTIPLE_RESOURCE_MATCH = /^(.+)\[(.+?),(.+)\]$/ # Matches a single resource lookup specification, # e.g., "service[nginx]" SINGLE_RESOURCE_MATCH = /^(.+)\[(.+)\]$/ attr_reader :iterator def initialize @resources = Array.new @resources_by_name = Hash.new @insert_after_idx = nil end def all_resources @resources end def [](index) @resources[index] end def []=(index, arg) is_chef_resource(arg) @resources[index] = arg @resources_by_name[arg.to_s] = index end def <<(*args) args.flatten.each do |a| is_chef_resource(a) @resources << a @resources_by_name[a.to_s] = @resources.length - 1 end self end # 'push' is an alias method to << alias_method :push, :<< def insert(resource) is_chef_resource(resource) if @insert_after_idx # in the middle of executing a run, so any resources inserted now should # be placed after the most recent addition done by the currently executing # resource @resources.insert(@insert_after_idx + 1, resource) # update name -> location mappings and register new resource @resources_by_name.each_key do |key| @resources_by_name[key] += 1 if @resources_by_name[key] > @insert_after_idx end @resources_by_name[resource.to_s] = @insert_after_idx + 1 @insert_after_idx += 1 else @resources << resource @resources_by_name[resource.to_s] = @resources.length - 1 end end def each @resources.each do |resource| yield resource end end def execute_each_resource(&resource_exec_block) @iterator = StepableIterator.for_collection(@resources) @iterator.each_with_index do |resource, idx| @insert_after_idx = idx yield resource end end def each_index @resources.each_index do |i| yield i end end def empty? @resources.empty? end def lookup(resource) lookup_by = nil if resource.kind_of?(Chef::Resource) lookup_by = resource.to_s elsif resource.kind_of?(String) lookup_by = resource else raise ArgumentError, "Must pass a Chef::Resource or String to lookup" end res = @resources_by_name[lookup_by] unless res raise Chef::Exceptions::ResourceNotFound, "Cannot find a resource matching #{lookup_by} (did you define it first?)" end @resources[res] end # Find existing resources by searching the list of existing resources. Possible # forms are: # # find(:file => "foobar") # find(:file => [ "foobar", "baz" ]) # find("file[foobar]", "file[baz]") # find("file[foobar,baz]") # # Returns the matching resource, or an Array of matching resources. # # Raises an ArgumentError if you feed it bad lookup information # Raises a Runtime Error if it can't find the resources you are looking for. def find(*args) results = Array.new args.each do |arg| case arg when Hash results << find_resource_by_hash(arg) when String results << find_resource_by_string(arg) else msg = "arguments to #{self.class.name}#find should be of the form :resource => 'name' or resource[name]" raise Chef::Exceptions::InvalidResourceSpecification, msg end end flat_results = results.flatten flat_results.length == 1 ? flat_results[0] : flat_results end # resources is a poorly named, but we have to maintain it for back # compat. alias_method :resources, :find # Returns true if +query_object+ is a valid string for looking up a # resource, or raises InvalidResourceSpecification if not. # === Arguments # * query_object should be a string of the form # "resource_type[resource_name]", a single element Hash (e.g., :service => # "apache2"), or a Chef::Resource (this is the happy path). Other arguments # will raise an exception. # === Returns # * true returns true for all valid input. # === Raises # * Chef::Exceptions::InvalidResourceSpecification for all invalid input. def validate_lookup_spec!(query_object) case query_object when Chef::Resource true when SINGLE_RESOURCE_MATCH, MULTIPLE_RESOURCE_MATCH true when Hash true when String raise Chef::Exceptions::InvalidResourceSpecification, "The string `#{query_object}' is not valid for resource collection lookup. Correct syntax is `resource_type[resource_name]'" else raise Chef::Exceptions::InvalidResourceSpecification, "The object `#{query_object.inspect}' is not valid for resource collection lookup. " + "Use a String like `resource_type[resource_name]' or a Chef::Resource object" end end # Serialize this object as a hash def to_json(*a) instance_vars = Hash.new self.instance_variables.each do |iv| instance_vars[iv] = self.instance_variable_get(iv) end results = { 'json_class' => self.class.name, 'instance_vars' => instance_vars } results.to_json(*a) end def self.json_create(o) collection = self.new() o["instance_vars"].each do |k,v| collection.instance_variable_set(k.to_sym, v) end collection end private def find_resource_by_hash(arg) results = Array.new arg.each do |resource_name, name_list| names = name_list.kind_of?(Array) ? name_list : [ name_list ] names.each do |name| res_name = "#{resource_name.to_s}[#{name}]" results << lookup(res_name) end end return results end def find_resource_by_string(arg) results = Array.new case arg when MULTIPLE_RESOURCE_MATCH resource_type = $1 arg =~ /^.+\[(.+)\]$/ resource_list = $1 resource_list.split(",").each do |name| resource_name = "#{resource_type}[#{name}]" results << lookup(resource_name) end when SINGLE_RESOURCE_MATCH resource_type = $1 name = $2 resource_name = "#{resource_type}[#{name}]" results << lookup(resource_name) else raise ArgumentError, "Bad string format #{arg}, you must have a string like resource_type[name]!" end return results end def is_chef_resource(arg) unless arg.kind_of?(Chef::Resource) raise ArgumentError, "Members must be Chef::Resource's" end true end end end chef-11.8.2/lib/chef/shell.rb0000644000004100000410000002110512254362222015646 0ustar www-datawww-data# Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 Daniel DeLeo # License:: Apache License, Version 2.0 # # 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. # require 'singleton' require 'pp' require 'etc' require 'mixlib/cli' require 'chef' require 'chef/version' require 'chef/client' require 'chef/config' require 'chef/config_fetcher' require 'chef/shell/shell_session' require 'chef/shell/ext' require 'chef/json_compat' # = Shell # Shell is Chef in an IRB session. Shell can interact with a Chef server via the # REST API, and run and debug recipes interactively. module Shell LEADERS = Hash.new("") LEADERS[Chef::Recipe] = ":recipe" LEADERS[Chef::Node] = ":attributes" class << self attr_accessor :client_type attr_accessor :options attr_accessor :env attr_writer :editor end # Start the irb REPL with chef-shell's customizations def self.start setup_logger # FUGLY HACK: irb gives us no other choice. irb_help = [:help, :irb_help, IRB::ExtendCommandBundle::NO_OVERRIDE] IRB::ExtendCommandBundle.instance_variable_get(:@ALIASES).delete(irb_help) parse_opts # HACK: this duplicates the functions of IRB.start, but we have to do it # to get access to the main object before irb starts. ::IRB.setup(nil) irb = IRB::Irb.new init(irb.context.main) irb_conf[:IRB_RC].call(irb.context) if irb_conf[:IRB_RC] irb_conf[:MAIN_CONTEXT] = irb.context trap("SIGINT") do irb.signal_handle end catch(:IRB_EXIT) do irb.eval_input end end def self.setup_logger Chef::Config[:log_level] ||= :warn # If log_level is auto, change it to warn Chef::Config[:log_level] = :warn if Chef::Config[:log_level] == :auto Chef::Log.init(STDERR) Mixlib::Authentication::Log.logger = Ohai::Log.logger = Chef::Log.logger Chef::Log.level = Chef::Config[:log_level] || :warn end # Shell assumes it's running whenever it is defined def self.running? true end # Set the irb_conf object to something other than IRB.conf # usful for testing. def self.irb_conf=(conf_hash) @irb_conf = conf_hash end def self.irb_conf @irb_conf || IRB.conf end def self.configure_irb irb_conf[:HISTORY_FILE] = "~/.chef/chef_shell_history" irb_conf[:SAVE_HISTORY] = 1000 irb_conf[:IRB_RC] = lambda do |conf| m = conf.main conf.prompt_c = "chef#{leader(m)} > " conf.return_format = " => %s \n" conf.prompt_i = "chef#{leader(m)} > " conf.prompt_n = "chef#{leader(m)} ?> " conf.prompt_s = "chef#{leader(m)}%l> " end end def self.leader(main_object) env_string = Shell.env ? " (#{Shell.env})" : "" LEADERS[main_object.class] + env_string end def self.session unless client_type.instance.node_built? puts "Session type: #{client_type.session_type}" client_type.instance.reset! end client_type.instance end def self.init(main) parse_json configure_irb session # trigger ohai run + session load session.node.consume_attributes(@json_attribs) Extensions.extend_context_object(main) main.version puts puts "run `help' for help, `exit' or ^D to quit." puts puts "Ohai2u#{greeting}!" end def self.greeting " #{Etc.getlogin}@#{Shell.session.node.fqdn}" rescue NameError, ArgumentError "" end def self.parse_json if Chef::Config[:json_attribs] config_fetcher = Chef::ConfigFetcher.new(Chef::Config[:json_attribs]) @json_attribs = config_fetcher.fetch_json end end def self.fatal!(message, exit_status) Chef::Log.fatal(message) exit exit_status end def self.client_type type = Shell::StandAloneSession type = Shell::SoloSession if Chef::Config[:shell_solo] type = Shell::ClientSession if Chef::Config[:client] type = Shell::DoppelGangerSession if Chef::Config[:doppelganger] type end def self.parse_opts @options = Options.new @options.parse_opts end def self.editor @editor || Chef::Config[:editor] || ENV['EDITOR'] end class Options include Mixlib::CLI def self.footer(text=nil) @footer = text if text @footer end banner("chef-shell #{Chef::VERSION}\n\nUsage: chef-shell [NAMED_CONF] (OPTIONS)") footer(<<-FOOTER) When no CONFIG is specified, chef-shell attempts to load a default configuration file: * If a NAMED_CONF is given, chef-shell will load ~/.chef/NAMED_CONF/chef_shell.rb * If no NAMED_CONF is given chef-shell will load ~/.chef/chef_shell.rb if it exists * chef-shell falls back to loading /etc/chef/client.rb or /etc/chef/solo.rb if -z or -s options are given and no chef_shell.rb can be found. FOOTER option :config_file, :short => "-c CONFIG", :long => "--config CONFIG", :description => "The configuration file to use" option :help, :short => "-h", :long => "--help", :description => "Show this message", :on => :tail, :boolean => true, :proc => proc { print_help } option :log_level, :short => "-l LOG_LEVEL", :long => '--log-level LOG_LEVEL', :description => "Set the logging level", :proc => proc { |level| Chef::Config.log_level = level.to_sym; Shell.setup_logger } option :standalone, :short => "-a", :long => "--standalone", :description => "standalone session", :default => true, :boolean => true option :shell_solo, :short => "-s", :long => "--solo", :description => "chef-solo session", :boolean => true, :proc => proc {Chef::Config[:solo] = true} option :client, :short => "-z", :long => "--client", :description => "chef-client session", :boolean => true option :json_attribs, :short => "-j JSON_ATTRIBS", :long => "--json-attributes JSON_ATTRIBS", :description => "Load attributes from a JSON file or URL", :proc => nil option :chef_server_url, :short => "-S CHEFSERVERURL", :long => "--server CHEFSERVERURL", :description => "The chef server URL", :proc => nil option :version, :short => "-v", :long => "--version", :description => "Show chef version", :boolean => true, :proc => lambda {|v| puts "Chef: #{::Chef::VERSION}"}, :exit => 0 def self.print_help instance = new instance.parse_options([]) puts instance.opt_parser puts puts footer puts exit 1 end def self.setup! self.new.parse_opts end def parse_opts remainder = parse_options environment = remainder.first # We have to nuke ARGV to make sure irb's option parser never sees it. # otherwise, IRB complains about command line switches it doesn't recognize. ARGV.clear config[:config_file] = config_file_for_shell_mode(environment) config_msg = config[:config_file] || "none (standalone session)" puts "loading configuration: #{config_msg}" Chef::Config.from_file(config[:config_file]) if !config[:config_file].nil? && File.exists?(config[:config_file]) && File.readable?(config[:config_file]) Chef::Config.merge!(config) end private def config_file_for_shell_mode(environment) if config[:config_file] config[:config_file] elsif environment && ENV['HOME'] Shell.env = environment config_file_to_try = ::File.join(ENV['HOME'], '.chef', environment, 'chef_shell.rb') unless ::File.exist?(config_file_to_try) puts "could not find chef-shell config for environment #{environment} at #{config_file_to_try}" exit 1 end config_file_to_try elsif ENV['HOME'] && ::File.exist?(File.join(ENV['HOME'], '.chef', 'chef_shell.rb')) File.join(ENV['HOME'], '.chef', 'chef_shell.rb') elsif config[:solo] "/etc/chef/solo.rb" elsif config[:client] "/etc/chef/client.rb" else nil end end end end chef-11.8.2/lib/chef/user.rb0000644000004100000410000001172012254362222015517 0ustar www-datawww-data# # Author:: Steven Danna (steve@opscode.com) # Copyright:: Copyright 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/config' require 'chef/mixin/params_validate' require 'chef/mixin/from_file' require 'chef/mash' require 'chef/json_compat' require 'chef/search/query' class Chef class User include Chef::Mixin::FromFile include Chef::Mixin::ParamsValidate def initialize @name = '' @public_key = nil @private_key = nil @password = nil @admin = false end def name(arg=nil) set_or_return(:name, arg, :regex => /^[a-z0-9\-_]+$/) end def admin(arg=nil) set_or_return(:admin, arg, :kind_of => [TrueClass, FalseClass]) end def public_key(arg=nil) set_or_return(:public_key, arg, :kind_of => String) end def private_key(arg=nil) set_or_return(:private_key, arg, :kind_of => String) end def password(arg=nil) set_or_return(:password, arg, :kind_of => String) end def to_hash result = { "name" => @name, "public_key" => @public_key, "admin" => @admin } result["private_key"] = @private_key if @private_key result["password"] = @password if @password result end def to_json(*a) to_hash.to_json(*a) end def destroy Chef::REST.new(Chef::Config[:chef_server_url]).delete_rest("users/#{@name}") end def create payload = {:name => self.name, :admin => self.admin, :password => self.password } payload[:public_key] = public_key if public_key new_user =Chef::REST.new(Chef::Config[:chef_server_url]).post_rest("users", payload) Chef::User.from_hash(self.to_hash.merge(new_user)) end def update(new_key=false) payload = {:name => name, :admin => admin} payload[:private_key] = new_key if new_key payload[:password] = password if password updated_user = Chef::REST.new(Chef::Config[:chef_server_url]).put_rest("users/#{name}", payload) Chef::User.from_hash(self.to_hash.merge(updated_user)) end def save(new_key=false) begin create rescue Net::HTTPServerException => e if e.response.code == "409" update(new_key) else raise e end end end def reregister r = Chef::REST.new(Chef::Config[:chef_server_url]) reregistered_self = r.put_rest("users/#{name}", { :name => name, :admin => admin, :private_key => true }) private_key(reregistered_self["private_key"]) self end def to_s "user[#{@name}]" end def inspect "Chef::User name:'#{name}' admin:'#{admin.inspect}'" + "public_key:'#{public_key}' private_key:#{private_key}" end # Class Methods def self.from_hash(user_hash) user = Chef::User.new user.name user_hash['name'] user.private_key user_hash['private_key'] if user_hash.key?('private_key') user.password user_hash['password'] if user_hash.key?('password') user.public_key user_hash['public_key'] user.admin user_hash['admin'] user end def self.from_json(json) Chef::User.from_hash(Chef::JSONCompat.from_json(json)) end class << self alias_method :json_create, :from_json end def self.list(inflate=false) response = if inflate users = Chef::REST.new(Chef::Config[:chef_server_url]).get_rest('users') users.map do |name| Chef::User.load(name) end else Chef::REST.new(Chef::Config[:chef_server_url]).get_rest('users') end if response.is_a? Array transform_ohc_list_response(response) else response end end def self.load(name) response = Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("users/#{name}") Chef::User.from_hash(response) end private # Gross. Transforms an API response in the form of: # [ { "user" => { "username" => USERNAME }}, ...] # into the form # { "USERNAME" => "URI" } def self.transform_ohc_list_response(response) new_response = Hash.new response.each do |u| name = u['user']['username'] new_response[name] = Chef::Config[:chef_server_url] + "/users/#{name}" end new_response end end end chef-11.8.2/lib/chef/version_constraint.rb0000644000004100000410000000674212254362222020502 0ustar www-datawww-data# Author:: Seth Falcon () # Author:: Christopher Walters () # Copyright:: Copyright 2010-2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'chef/version_class' class Chef class VersionConstraint DEFAULT_CONSTRAINT = ">= 0.0.0" STANDARD_OPS = %w(< > <= >=) OPS = %w(< > = <= >= ~>) PATTERN = /^(#{OPS.join('|')}) (.+)$/ VERSION_CLASS = Chef::Version attr_reader :op, :version def initialize(constraint_spec=DEFAULT_CONSTRAINT) case constraint_spec when nil parse(DEFAULT_CONSTRAINT) when Array parse_from_array(constraint_spec) when String parse(constraint_spec) else msg = "VersionConstraint should be created from a String. You gave: #{constraint_spec.inspect}" raise Chef::Exceptions::InvalidVersionConstraint, msg end end def include?(v) version = if v.respond_to? :version # a CookbookVersion-like object self.class::VERSION_CLASS.new(v.version.to_s) else self.class::VERSION_CLASS.new(v.to_s) end do_op(version) end def inspect "(#{@op} #{@version})" end def to_s "#{@op} #{@version}" end def eql?(o) o.class == self.class && @op == o.op && @version == o.version end alias_method :==, :eql? private def do_op(other_version) if STANDARD_OPS.include? @op other_version.send(@op.to_sym, @version) elsif @op == '=' other_version == @version elsif @op == '~>' if @missing_patch_level (other_version.major == @version.major && other_version.minor >= @version.minor) else (other_version.major == @version.major && other_version.minor == @version.minor && other_version.patch >= @version.patch) end else # should never happen raise "bad op #{@op}" end end def parse_from_array(constraint_spec) if constraint_spec.empty? parse(DEFAULT_CONSTRAINT) elsif constraint_spec.size == 1 parse(constraint_spec.first) else msg = "only one version constraint operation is supported, but you gave #{constraint_spec.size} " msg << "['#{constraint_spec.join(', ')}']" raise Chef::Exceptions::InvalidVersionConstraint, msg end end def parse(str) @missing_patch_level = false if str.index(" ").nil? && str =~ /^[0-9]/ # try for lone version, implied '=' @version = self.class::VERSION_CLASS.new(str) @op = "=" elsif PATTERN.match str @op = $1 raw_version = $2 @version = self.class::VERSION_CLASS.new(raw_version) if raw_version.split('.').size <= 2 @missing_patch_level = true end else raise Chef::Exceptions::InvalidVersionConstraint, "'#{str}'" end end end end chef-11.8.2/lib/chef/cookbook_loader.rb0000644000004100000410000001077512254362222017706 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Walters () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # Copyright:: Copyright (c) 2009 Daniel DeLeo # License:: Apache License, Version 2.0 # # 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. require 'chef/config' require 'chef/exceptions' require 'chef/cookbook/cookbook_version_loader' require 'chef/cookbook_version' require 'chef/cookbook/chefignore' require 'chef/cookbook/metadata' # # CookbookLoader class loads the cookbooks lazily as read # class Chef class CookbookLoader attr_reader :cookbooks_by_name attr_reader :merged_cookbooks attr_reader :cookbook_paths attr_reader :metadata include Enumerable def initialize(*repo_paths) repo_paths = repo_paths.flatten raise ArgumentError, "You must specify at least one cookbook repo path" if repo_paths.empty? @cookbooks_by_name = Mash.new @loaded_cookbooks = {} @metadata = Mash.new @cookbooks_paths = Hash.new {|h,k| h[k] = []} # for deprecation warnings @chefignores = {} @repo_paths = repo_paths.map do |repo_path| repo_path = File.expand_path(repo_path) end # Used to track which cookbooks appear in multiple places in the cookbook repos # and are merged in to a single cookbook by file shadowing. This behavior is # deprecated, so users of this class may issue warnings to the user by checking # this variable @merged_cookbooks = [] end def merged_cookbook_paths # for deprecation warnings merged_cookbook_paths = {} @merged_cookbooks.each {|c| merged_cookbook_paths[c] = @cookbooks_paths[c]} merged_cookbook_paths end def load_cookbooks @repo_paths.each do |repo_path| Dir[File.join(repo_path, "*")].each do |cookbook_path| load_cookbook(File.basename(cookbook_path), [repo_path]) end end @cookbooks_by_name end def load_cookbook(cookbook_name, repo_paths=nil) repo_paths ||= @repo_paths repo_paths.each do |repo_path| @chefignores[repo_path] ||= Cookbook::Chefignore.new(repo_path) cookbook_path = File.join(repo_path, cookbook_name.to_s) next unless File.directory?(cookbook_path) and Dir[File.join(repo_path, "*")].include?(cookbook_path) loader = Cookbook::CookbookVersionLoader.new(cookbook_path, @chefignores[repo_path]) loader.load_cookbooks next if loader.empty? cookbook_name = loader.cookbook_name @cookbooks_paths[cookbook_name] << cookbook_path # for deprecation warnings if @loaded_cookbooks.key?(cookbook_name) @merged_cookbooks << cookbook_name # for deprecation warnings @loaded_cookbooks[cookbook_name].merge!(loader) else @loaded_cookbooks[cookbook_name] = loader end end if @loaded_cookbooks.has_key?(cookbook_name) cookbook_version = @loaded_cookbooks[cookbook_name].cookbook_version @cookbooks_by_name[cookbook_name] = cookbook_version @metadata[cookbook_name] = cookbook_version.metadata end @cookbooks_by_name[cookbook_name] end def [](cookbook) if @cookbooks_by_name.has_key?(cookbook.to_sym) or load_cookbook(cookbook.to_sym) @cookbooks_by_name[cookbook.to_sym] else raise Exceptions::CookbookNotFoundInRepo, "Cannot find a cookbook named #{cookbook.to_s}; did you forget to add metadata to a cookbook? (http://wiki.opscode.com/display/chef/Metadata)" end end alias :fetch :[] def has_key?(cookbook_name) not self[cookbook_name.to_sym].nil? end alias :cookbook_exists? :has_key? alias :key? :has_key? def each @cookbooks_by_name.keys.sort { |a,b| a.to_s <=> b.to_s }.each do |cname| yield(cname, @cookbooks_by_name[cname]) end end def cookbook_names @cookbooks_by_name.keys.sort end def values @cookbooks_by_name.values end alias :cookbooks :values end end chef-11.8.2/lib/chef/provider/0000755000004100000410000000000012254362222016045 5ustar www-datawww-datachef-11.8.2/lib/chef/provider/cookbook_file.rb0000644000004100000410000000251712254362222021204 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/file' require 'chef/deprecation/provider/cookbook_file' require 'chef/deprecation/warnings' class Chef class Provider class CookbookFile < Chef::Provider::File extend Chef::Deprecation::Warnings include Chef::Deprecation::Provider::CookbookFile add_deprecation_warnings_for(Chef::Deprecation::Provider::CookbookFile.instance_methods) def initialize(new_resource, run_context) @content_class = Chef::Provider::CookbookFile::Content super end def load_current_resource @current_resource = Chef::Resource::CookbookFile.new(@new_resource.name) super end end end end chef-11.8.2/lib/chef/provider/ruby_block.rb0000644000004100000410000000220112254362222020520 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: AJ Christensen () # Copyright:: Copyright (c) 2009 Opscode # License:: Apache License, Version 2.0 # # 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. # class Chef class Provider class RubyBlock < Chef::Provider def whyrun_supported? true end def load_current_resource true end def action_run converge_by("execute the ruby block #{@new_resource.name}") do @new_resource.block.call Chef::Log.info("#{@new_resource} called") end end alias :action_create :action_run end end end chef-11.8.2/lib/chef/provider/git.rb0000644000004100000410000002745012254362222017165 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/log' require 'chef/provider' require 'chef/mixin/shell_out' require 'fileutils' class Chef class Provider class Git < Chef::Provider include Chef::Mixin::ShellOut def whyrun_supported? true end def load_current_resource @resolved_reference = nil @current_resource = Chef::Resource::Git.new(@new_resource.name) if current_revision = find_current_revision @current_resource.revision current_revision end end def define_resource_requirements # Parent directory of the target must exist. requirements.assert(:checkout, :sync) do |a| dirname = ::File.dirname(@new_resource.destination) a.assertion { ::File.directory?(dirname) } a.whyrun("Directory #{dirname} does not exist, this run will fail unless it has been previously created. Assuming it would have been created.") a.failure_message(Chef::Exceptions::MissingParentDirectory, "Cannot clone #{@new_resource} to #{@new_resource.destination}, the enclosing directory #{dirname} does not exist") end requirements.assert(:all_actions) do |a| a.assertion { !(@new_resource.revision =~ /^origin\//) } a.failure_message Chef::Exceptions::InvalidRemoteGitReference, "Deploying remote branches is not supported. " + "Specify the remote branch as a local branch for " + "the git repository you're deploying from " + "(ie: '#{@new_resource.revision.gsub('origin/', '')}' rather than '#{@new_resource.revision}')." end requirements.assert(:all_actions) do |a| # this can't be recovered from in why-run mode, because nothing that # we do in the course of a run is likely to create a valid target_revision # if we can't resolve it up front. a.assertion { target_revision != nil } a.failure_message Chef::Exceptions::UnresolvableGitReference, "Unable to parse SHA reference for '#{@new_resource.revision}' in repository '#{@new_resource.repository}'. " + "Verify your (case-sensitive) repository URL and revision.\n" + "`git ls-remote` output: #{@resolved_reference}" end end def action_checkout if target_dir_non_existent_or_empty? clone checkout enable_submodules add_remotes else Chef::Log.debug "#{@new_resource} checkout destination #{@new_resource.destination} already exists or is a non-empty directory" end end def action_export action_checkout converge_by("complete the export by removing #{@new_resource.destination}.git after checkout") do FileUtils.rm_rf(::File.join(@new_resource.destination,".git")) end end def action_sync if existing_git_clone? current_rev = find_current_revision Chef::Log.debug "#{@new_resource} current revision: #{current_rev} target revision: #{target_revision}" unless current_revision_matches_target_revision? fetch_updates enable_submodules Chef::Log.info "#{@new_resource} updated to revision #{target_revision}" end add_remotes else action_checkout end end def existing_git_clone? ::File.exist?(::File.join(@new_resource.destination, ".git")) end def target_dir_non_existent_or_empty? !::File.exist?(@new_resource.destination) || Dir.entries(@new_resource.destination).sort == ['.','..'] end def find_current_revision Chef::Log.debug("#{@new_resource} finding current git revision") if ::File.exist?(::File.join(cwd, ".git")) # 128 is returned when we're not in a git repo. this is fine result = shell_out!('git rev-parse HEAD', :cwd => cwd, :returns => [0,128]).stdout.strip end sha_hash?(result) ? result : nil end def add_remotes if (@new_resource.additional_remotes.length > 0) @new_resource.additional_remotes.each_pair do |remote_name, remote_url| converge_by("add remote #{remote_name} from #{remote_url}") do Chef::Log.info "#{@new_resource} adding git remote #{remote_name} = #{remote_url}" setup_remote_tracking_branches(remote_name, remote_url) end end end end def clone converge_by("clone from #{@new_resource.repository} into #{@new_resource.destination}") do remote = @new_resource.remote args = [] args << "-o #{remote}" unless remote == 'origin' args << "--depth #{@new_resource.depth}" if @new_resource.depth Chef::Log.info "#{@new_resource} cloning repo #{@new_resource.repository} to #{@new_resource.destination}" clone_cmd = "git clone #{args.join(' ')} \"#{@new_resource.repository}\" \"#{@new_resource.destination}\"" shell_out!(clone_cmd, run_options) end end def checkout sha_ref = target_revision converge_by("checkout ref #{sha_ref} branch #{@new_resource.revision}") do # checkout into a local branch rather than a detached HEAD shell_out!("git checkout -b deploy #{sha_ref}", run_options(:cwd => @new_resource.destination)) Chef::Log.info "#{@new_resource} checked out branch: #{@new_resource.revision} reference: #{sha_ref}" end end def enable_submodules if @new_resource.enable_submodules converge_by("enable git submodules for #{@new_resource}") do Chef::Log.info "#{@new_resource} synchronizing git submodules" command = "git submodule sync" shell_out!(command, run_options(:cwd => @new_resource.destination)) Chef::Log.info "#{@new_resource} enabling git submodules" # the --recursive flag means we require git 1.6.5+ now, see CHEF-1827 command = "git submodule update --init --recursive" shell_out!(command, run_options(:cwd => @new_resource.destination)) end end end def fetch_updates setup_remote_tracking_branches(@new_resource.remote, @new_resource.repository) converge_by("fetch updates for #{@new_resource.remote}") do # since we're in a local branch already, just reset to specified revision rather than merge fetch_command = "git fetch #{@new_resource.remote} && git fetch #{@new_resource.remote} --tags && git reset --hard #{target_revision}" Chef::Log.debug "Fetching updates from #{new_resource.remote} and resetting to revision #{target_revision}" shell_out!(fetch_command, run_options(:cwd => @new_resource.destination)) end end def setup_remote_tracking_branches(remote_name, remote_url) converge_by("set up remote tracking branches for #{remote_url} at #{remote_name}") do Chef::Log.debug "#{@new_resource} configuring remote tracking branches for repository #{remote_url} "+ "at remote #{remote_name}" check_remote_command = "git config --get remote.#{remote_name}.url" remote_status = shell_out!(check_remote_command, run_options(:cwd => @new_resource.destination, :returns => [0,1,2])) case remote_status.exitstatus when 0, 2 # * Status 0 means that we already have a remote with this name, so we should update the url # if it doesn't match the url we want. # * Status 2 means that we have multiple urls assigned to the same remote (not a good idea) # which we can fix by replacing them all with our target url (hence the --replace-all option) if multiple_remotes?(remote_status) || !remote_matches?(remote_url,remote_status) update_remote_url_command = "git config --replace-all remote.#{remote_name}.url #{remote_url}" shell_out!(update_remote_url_command, run_options(:cwd => @new_resource.destination)) end when 1 add_remote_command = "git remote add #{remote_name} #{remote_url}" shell_out!(add_remote_command, run_options(:cwd => @new_resource.destination)) end end end def multiple_remotes?(check_remote_command_result) check_remote_command_result.exitstatus == 2 end def remote_matches?(remote_url, check_remote_command_result) check_remote_command_result.stdout.strip.eql?(remote_url) end def current_revision_matches_target_revision? (!@current_resource.revision.nil?) && (target_revision.strip.to_i(16) == @current_resource.revision.strip.to_i(16)) end def target_revision @target_revision ||= begin if sha_hash?(@new_resource.revision) @target_revision = @new_resource.revision else @target_revision = remote_resolve_reference end end end alias :revision_slug :target_revision def remote_resolve_reference Chef::Log.debug("#{@new_resource} resolving remote reference") # The sha pointed to by an annotated tag is identified by the # '^{}' suffix appended to the tag. In order to resolve # annotated tags, we have to search for "revision*" and # post-process. Special handling for 'HEAD' to ignore a tag # named 'HEAD'. rev_pattern = case @new_resource.revision when '', 'HEAD' 'HEAD' else @new_resource.revision + '*' end command = git("ls-remote \"#{@new_resource.repository}\"", rev_pattern) @resolved_reference = shell_out!(command, run_options).stdout ref_lines = @resolved_reference.split("\n") refs = ref_lines.map { |line| line.split("\t") } # first try for ^{} indicating the commit pointed to by an # annotated tag tagged_commit = refs.find { |m| m[1].end_with?("#{@new_resource.revision}^{}") } # It is possible for a user to create a tag named 'HEAD'. # Using such a degenerate annotated tag would be very # confusing. We avoid the issue by disallowing the use of # annotated tags named 'HEAD'. if tagged_commit && rev_pattern != 'HEAD' tagged_commit[0] else found = refs.find { |m| m[1].end_with?(@new_resource.revision) } if found found[0] else nil end end end private def run_options(run_opts={}) run_opts[:user] = @new_resource.user if @new_resource.user run_opts[:group] = @new_resource.group if @new_resource.group run_opts[:environment] = {"GIT_SSH" => @new_resource.ssh_wrapper} if @new_resource.ssh_wrapper run_opts[:log_tag] = @new_resource.to_s run_opts[:timeout] = @new_resource.timeout if @new_resource.timeout run_opts end def cwd @new_resource.destination end def git(*args) ["git", *args].compact.join(" ") end def sha_hash?(string) string =~ /^[0-9a-f]{40}$/ end end end end chef-11.8.2/lib/chef/provider/directory.rb0000644000004100000410000001163012254362222020377 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/config' require 'chef/log' require 'chef/resource/directory' require 'chef/provider' require 'chef/provider/file' require 'fileutils' class Chef class Provider class Directory < Chef::Provider::File def whyrun_supported? true end def load_current_resource @current_resource = Chef::Resource::Directory.new(@new_resource.name) @current_resource.path(@new_resource.path) if ::File.exists?(@current_resource.path) && @action != :create_if_missing load_resource_attributes_from_file(@current_resource) end @current_resource end def define_resource_requirements requirements.assert(:create) do |a| # Make sure the parent dir exists, or else fail. # for why run, print a message explaining the potential error. parent_directory = ::File.dirname(@new_resource.path) a.assertion { @new_resource.recursive || ::File.directory?(parent_directory) } a.failure_message(Chef::Exceptions::EnclosingDirectoryDoesNotExist, "Parent directory #{parent_directory} does not exist, cannot create #{@new_resource.path}") a.whyrun("Assuming directory #{parent_directory} would have been created") end requirements.assert(:create) do |a| parent_directory = ::File.dirname(@new_resource.path) a.assertion do if @new_resource.recursive # find the lowest-level directory in @new_resource.path that already exists # make sure we have write permissions to that directory is_parent_writable = lambda do |base_dir| base_dir = ::File.dirname(base_dir) if ::File.exists?(base_dir) ::File.writable?(base_dir) else is_parent_writable.call(base_dir) end end is_parent_writable.call(@new_resource.path) else # in why run mode & parent directory does not exist no permissions check is required # If not in why run, permissions must be valid and we rely on prior assertion that dir exists if !whyrun_mode? || ::File.exists?(parent_directory) ::File.writable?(parent_directory) else true end end end a.failure_message(Chef::Exceptions::InsufficientPermissions, "Cannot create #{@new_resource} at #{@new_resource.path} due to insufficient permissions") end requirements.assert(:delete) do |a| a.assertion do if ::File.exists?(@new_resource.path) ::File.directory?(@new_resource.path) && ::File.writable?(@new_resource.path) else true end end a.failure_message(RuntimeError, "Cannot delete #{@new_resource} at #{@new_resource.path}!") # No why-run handling here: # * if we don't have permissions, this is unlikely to be changed earlier in the run # * if the target is a file (not a dir), there's no reasonable path by which this would have been changed end end def action_create unless ::File.exists?(@new_resource.path) converge_by("create new directory #{@new_resource.path}") do if @new_resource.recursive == true ::FileUtils.mkdir_p(@new_resource.path) else ::Dir.mkdir(@new_resource.path) end Chef::Log.info("#{@new_resource} created directory #{@new_resource.path}") end end do_acl_changes do_selinux(true) load_resource_attributes_from_file(@new_resource) end def action_delete if ::File.exists?(@new_resource.path) converge_by("delete existing directory #{@new_resource.path}") do if @new_resource.recursive == true FileUtils.rm_rf(@new_resource.path) Chef::Log.info("#{@new_resource} deleted #{@new_resource.path} recursively") else ::Dir.delete(@new_resource.path) Chef::Log.info("#{@new_resource} deleted #{@new_resource.path}") end end end end end end end chef-11.8.2/lib/chef/provider/http_request.rb0000644000004100000410000001001312254362222021114 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'tempfile' require 'chef/http/simple' class Chef class Provider class HttpRequest < Chef::Provider attr_accessor :http def whyrun_supported? true end def load_current_resource @http = Chef::HTTP::Simple.new(@new_resource.url) end # Send a HEAD request to @new_resource.url, with ?message=@new_resource.message def action_head message = check_message(@new_resource.message) # returns true from Chef::REST if returns 2XX (Net::HTTPSuccess) modified = @http.head( "#{@new_resource.url}?message=#{message}", @new_resource.headers ) Chef::Log.info("#{@new_resource} HEAD to #{@new_resource.url} successful") Chef::Log.debug("#{@new_resource} HEAD request response: #{modified}") # :head is usually used to trigger notifications, which converge_by now does if modified converge_by("#{@new_resource} HEAD to #{@new_resource.url} returned modified, trigger notifications") {} end end # Send a GET request to @new_resource.url, with ?message=@new_resource.message def action_get converge_by("#{@new_resource} GET to #{@new_resource.url}") do message = check_message(@new_resource.message) body = @http.get( "#{@new_resource.url}?message=#{message}", @new_resource.headers ) Chef::Log.info("#{@new_resource} GET to #{@new_resource.url} successful") Chef::Log.debug("#{@new_resource} GET request response: #{body}") end end # Send a PUT request to @new_resource.url, with the message as the payload def action_put converge_by("#{@new_resource} PUT to #{@new_resource.url}") do message = check_message(@new_resource.message) body = @http.put( "#{@new_resource.url}", message, @new_resource.headers ) Chef::Log.info("#{@new_resource} PUT to #{@new_resource.url} successful") Chef::Log.debug("#{@new_resource} PUT request response: #{body}") end end # Send a POST request to @new_resource.url, with the message as the payload def action_post converge_by("#{@new_resource} POST to #{@new_resource.url}") do message = check_message(@new_resource.message) body = @http.post( "#{@new_resource.url}", message, @new_resource.headers ) Chef::Log.info("#{@new_resource} POST to #{@new_resource.url} message: #{message.inspect} successful") Chef::Log.debug("#{@new_resource} POST request response: #{body}") end end # Send a DELETE request to @new_resource.url def action_delete converge_by("#{@new_resource} DELETE to #{@new_resource.url}") do body = @http.delete( "#{@new_resource.url}", @new_resource.headers ) @new_resource.updated_by_last_action(true) Chef::Log.info("#{@new_resource} DELETE to #{@new_resource.url} successful") Chef::Log.debug("#{@new_resource} DELETE request response: #{body}") end end private def check_message(message) if message.kind_of?(Proc) message.call else message end end end end end chef-11.8.2/lib/chef/provider/breakpoint.rb0000644000004100000410000000205012254362222020525 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Provider class Breakpoint < Chef::Provider def load_current_resource end def action_break if defined?(Shell) && Shell.running? run_context.resource_collection.iterator.pause @new_resource.updated_by_last_action(true) run_context.resource_collection.iterator end end end end end chef-11.8.2/lib/chef/provider/remote_directory.rb0000644000004100000410000001547512254362222021765 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/file' require 'chef/provider/directory' require 'chef/resource/directory' require 'chef/resource/remote_file' require 'chef/mixin/file_class' require 'chef/platform' require 'uri' require 'tempfile' require 'net/https' require 'set' class Chef class Provider class RemoteDirectory < Chef::Provider::Directory include Chef::Mixin::FileClass def action_create super files_to_purge = Set.new(Dir.glob(::File.join(@new_resource.path, '**', '*'), ::File::FNM_DOTMATCH).select do |name| name !~ /(?:^|#{Regexp.escape(::File::SEPARATOR)})\.\.?$/ end) files_to_transfer.each do |cookbook_file_relative_path| create_cookbook_file(cookbook_file_relative_path) # the file is removed from the purge list files_to_purge.delete(::File.join(@new_resource.path, cookbook_file_relative_path)) # parent directories are also removed from the purge list directories=::File.dirname(::File.join(@new_resource.path, cookbook_file_relative_path)).split(::File::SEPARATOR) for i in 0..directories.length-1 files_to_purge.delete(::File.join(directories[0..i])) end end purge_unmanaged_files(files_to_purge) end def action_create_if_missing # if this action is called, ignore the existing overwrite flag @new_resource.overwrite(false) action_create end protected def purge_unmanaged_files(unmanaged_files) if @new_resource.purge unmanaged_files.sort.reverse.each do |f| # file_class comes from Chef::Mixin::FileClass if ::File.directory?(f) && !Chef::Platform.windows? && !file_class.symlink?(f.dup) # Linux treats directory symlinks as files # Remove a directory as a directory when not on windows if it is not a symlink purge_directory(f) elsif ::File.directory?(f) && Chef::Platform.windows? # Windows treats directory symlinks as directories so we delete them here purge_directory(f) else converge_by("delete unmanaged file #{f}") do ::File.delete(f) Chef::Log.debug("#{@new_resource} deleted file #{f}") end end end end end def purge_directory(dir) converge_by("delete unmanaged directory #{dir}") do Dir::rmdir(dir) Chef::Log.debug("#{@new_resource} removed directory #{dir}") end end def files_to_transfer cookbook = run_context.cookbook_collection[resource_cookbook] files = cookbook.relative_filenames_in_preferred_directory(node, :files, @new_resource.source) files.sort.reverse end def directory_root_in_cookbook_cache @directory_root_in_cookbook_cache ||= begin cookbook = run_context.cookbook_collection[resource_cookbook] cookbook.preferred_filename_on_disk_location(node, :files, @new_resource.source, @new_resource.path) end end # Determine the cookbook to get the file from. If new resource sets an # explicit cookbook, use it, otherwise fall back to the implicit cookbook # i.e., the cookbook the resource was declared in. def resource_cookbook @new_resource.cookbook || @new_resource.cookbook_name end def create_cookbook_file(cookbook_file_relative_path) full_path = ::File.join(@new_resource.path, cookbook_file_relative_path) ensure_directory_exists(::File.dirname(full_path)) file_to_fetch = cookbook_file_resource(full_path, cookbook_file_relative_path) if @new_resource.overwrite file_to_fetch.run_action(:create) else file_to_fetch.run_action(:create_if_missing) end @new_resource.updated_by_last_action(true) if file_to_fetch.updated? end def cookbook_file_resource(target_path, relative_source_path) cookbook_file = Chef::Resource::CookbookFile.new(target_path, run_context) cookbook_file.cookbook_name = @new_resource.cookbook || @new_resource.cookbook_name cookbook_file.source(::File.join(@new_resource.source, relative_source_path)) if Chef::Platform.windows? && @new_resource.files_rights @new_resource.files_rights.each_pair do |permission, *args| cookbook_file.rights(permission, *args) end end cookbook_file.mode(@new_resource.files_mode) if @new_resource.files_mode cookbook_file.group(@new_resource.files_group) if @new_resource.files_group cookbook_file.owner(@new_resource.files_owner) if @new_resource.files_owner cookbook_file.backup(@new_resource.files_backup) if @new_resource.files_backup cookbook_file end def ensure_directory_exists(path) unless ::File.directory?(path) directory_to_create = resource_for_directory(path) directory_to_create.run_action(:create) @new_resource.updated_by_last_action(true) if directory_to_create.updated? end end def resource_for_directory(path) dir = Chef::Resource::Directory.new(path, run_context) dir.cookbook_name = @new_resource.cookbook || @new_resource.cookbook_name if Chef::Platform.windows? && @new_resource.rights # rights are only meant to be applied to the toppest-level directory; # Windows will handle inheritance. if path == @new_resource.path @new_resource.rights.each do |rights| #rights is a hash permissions = rights.delete(:permissions) #delete will return the value or nil if not found principals = rights.delete(:principals) dir.rights(permissions, principals, rights) end end end dir.mode(@new_resource.mode) if @new_resource.mode dir.group(@new_resource.group) dir.owner(@new_resource.owner) dir.recursive(true) dir end def whyrun_supported? true end end end end chef-11.8.2/lib/chef/provider/execute.rb0000644000004100000410000000542612254362222020043 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/mixin/shell_out' require 'chef/log' require 'chef/provider' class Chef class Provider class Execute < Chef::Provider include Chef::Mixin::ShellOut def load_current_resource true end def whyrun_supported? true end def action_run opts = {} if sentinel_file = sentinel_file_if_exists Chef::Log.debug("#{@new_resource} sentinel file #{sentinel_file} exists - nothing to do") return false end # original implementation did not specify a timeout, but ShellOut # *always* times out. So, set a very long default timeout opts[:timeout] = @new_resource.timeout || 3600 opts[:returns] = @new_resource.returns if @new_resource.returns opts[:environment] = @new_resource.environment if @new_resource.environment opts[:user] = @new_resource.user if @new_resource.user opts[:group] = @new_resource.group if @new_resource.group opts[:cwd] = @new_resource.cwd if @new_resource.cwd opts[:umask] = @new_resource.umask if @new_resource.umask opts[:log_level] = :info opts[:log_tag] = @new_resource.to_s if STDOUT.tty? && !Chef::Config[:daemon] && Chef::Log.info? opts[:live_stream] = STDOUT end converge_by("execute #{@new_resource.command}") do result = shell_out!(@new_resource.command, opts) Chef::Log.info("#{@new_resource} ran successfully") end end private def sentinel_file_if_exists if sentinel_file = @new_resource.creates relative = Pathname(sentinel_file).relative? cwd = @new_resource.cwd if relative && !cwd Chef::Log.warn "You have provided relative path for execute#creates (#{sentinel_file}) without execute#cwd (see CHEF-3819)" end if ::File.exists?(sentinel_file) sentinel_file elsif cwd && relative sentinel_file = ::File.join(cwd, sentinel_file) sentinel_file if ::File.exists?(sentinel_file) end end end end end end chef-11.8.2/lib/chef/provider/ifconfig.rb0000644000004100000410000001665612254362222020174 0ustar www-datawww-data# # Author:: Jason K. Jackson (jasonjackson@gmail.com) # Copyright:: Copyright (c) 2009 Jason K. Jackson # License:: Apache License, Version 2.0 # # 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. # require 'chef/log' require 'chef/mixin/command' require 'chef/provider' require 'chef/exceptions' require 'erb' # Recipe example: # # int = {Hash with your network settings...} # # ifconfig int['ip'] do # ignore_failure true # device int['dev'] # mask int['mask'] # gateway int['gateway'] # mtu int['mtu'] # end class Chef class Provider class Ifconfig < Chef::Provider include Chef::Mixin::Command attr_accessor :config_template attr_accessor :config_path def initialize(new_resource, run_context) super(new_resource, run_context) @config_template = nil @config_path = nil end def whyrun_supported? true end def load_current_resource @current_resource = Chef::Resource::Ifconfig.new(@new_resource.name) @ifconfig_success = true @interfaces = {} @status = popen4("ifconfig") do |pid, stdin, stdout, stderr| stdout.each do |line| if !line[0..9].strip.empty? @int_name = line[0..9].strip @interfaces[@int_name] = {"hwaddr" => (line =~ /(HWaddr)/ ? ($') : "nil").strip.chomp } else @interfaces[@int_name]["inet_addr"] = (line =~ /inet addr:(\S+)/ ? ($1) : "nil") if line =~ /inet addr:/ @interfaces[@int_name]["bcast"] = (line =~ /Bcast:(\S+)/ ? ($1) : "nil") if line =~ /Bcast:/ @interfaces[@int_name]["mask"] = (line =~ /Mask:(\S+)/ ? ($1) : "nil") if line =~ /Mask:/ @interfaces[@int_name]["mtu"] = (line =~ /MTU:(\S+)/ ? ($1) : "nil") if line =~ /MTU:/ @interfaces[@int_name]["metric"] = (line =~ /Metric:(\S+)/ ? ($1) : "nil") if line =~ /Metric:/ end if @interfaces.has_key?(@new_resource.device) @interface = @interfaces.fetch(@new_resource.device) @current_resource.target(@new_resource.target) @current_resource.device(@new_resource.device) @current_resource.inet_addr(@interface["inet_addr"]) @current_resource.hwaddr(@interface["hwaddr"]) @current_resource.bcast(@interface["bcast"]) @current_resource.mask(@interface["mask"]) @current_resource.mtu(@interface["mtu"]) @current_resource.metric(@interface["metric"]) end end end @current_resource end def define_resource_requirements requirements.assert(:all_actions) do |a| a.assertion { @status.exitstatus == 0 } a.failure_message Chef::Exceptions::Ifconfig, "ifconfig failed - #{@status.inspect}!" # no whyrun - if the base ifconfig used in load_current_resource fails # there's no reasonable action that could have been taken in the course of # a chef run to fix it. end end def action_add # check to see if load_current_resource found interface in ifconfig unless @current_resource.inet_addr unless @new_resource.device == loopback_device command = add_command converge_by ("run #{command} to add #{@new_resource}") do run_command( :command => command ) Chef::Log.info("#{@new_resource} added") # Write out the config files generate_config end end end end def action_enable # check to see if load_current_resource found ifconfig # enables, but does not manage config files unless @current_resource.inet_addr unless @new_resource.device == loopback_device command = enable_command converge_by ("run #{command} to enable #{@new_resource}") do run_command( :command => command ) Chef::Log.info("#{@new_resource} enabled") end end end end def action_delete # check to see if load_current_resource found the interface if @current_resource.device command = delete_command converge_by ("run #{command} to delete #{@new_resource}") do run_command( :command => command ) delete_config Chef::Log.info("#{@new_resource} deleted") end else Chef::Log.debug("#{@new_resource} does not exist - nothing to do") end end def action_disable # check to see if load_current_resource found the interface # disables, but leaves config files in place. if @current_resource.device command = disable_command converge_by ("run #{command} to disable #{@new_resource}") do run_command( :command => command ) Chef::Log.info("#{@new_resource} disabled") end else Chef::Log.debug("#{@new_resource} does not exist - nothing to do") end end def can_generate_config? ! @config_template.nil? and ! @config_path.nil? end def generate_config return unless can_generate_config? b = binding template = ::ERB.new(@config_template) converge_by ("generate configuration file : #{@config_path}") do network_file = ::File.new(@config_path, "w") network_file.puts(template.result(b)) network_file.close end Chef::Log.info("#{@new_resource} created configuration file") end def delete_config return unless can_generate_config? require 'fileutils' if ::File.exist?(@config_path) converge_by ("delete the #{@config_path}") do FileUtils.rm_f(@config_path, :verbose => false) end end Chef::Log.info("#{@new_resource} deleted configuration file") end private def add_command command = "ifconfig #{@new_resource.device} #{@new_resource.name}" command << " netmask #{@new_resource.mask}" if @new_resource.mask command << " metric #{@new_resource.metric}" if @new_resource.metric command << " mtu #{@new_resource.mtu}" if @new_resource.mtu command end def enable_command command = "ifconfig #{@new_resource.device} #{@new_resource.name}" command << " netmask #{@new_resource.mask}" if @new_resource.mask command << " metric #{@new_resource.metric}" if @new_resource.metric command << " mtu #{@new_resource.mtu}" if @new_resource.mtu command end def disable_command "ifconfig #{@new_resource.device} down" end def delete_command "ifconfig #{@new_resource.device} down" end def loopback_device 'lo' end end end end chef-11.8.2/lib/chef/provider/mount.rb0000644000004100000410000000721312254362222017537 0ustar www-datawww-data# # Author:: Joshua Timberman () # Copyright:: Copyright (c) 2009 Opscode, Inc # License:: Apache License, Version 2.0 # # 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. # require 'chef/log' require 'chef/mixin/command' require 'chef/provider' class Chef class Provider class Mount < Chef::Provider include Chef::Mixin::Command def whyrun_supported? true end def load_current_resource true end def action_mount unless @current_resource.mounted converge_by("mount #{@current_resource.device} to #{@current_resource.mount_point}") do status = mount_fs() if status Chef::Log.info("#{@new_resource} mounted") end end else Chef::Log.debug("#{@new_resource} is already mounted") end end def action_umount if @current_resource.mounted converge_by("unmount #{@current_resource.device}") do status = umount_fs() if status Chef::Log.info("#{@new_resource} unmounted") end end else Chef::Log.debug("#{@new_resource} is already unmounted") end end def action_remount unless @new_resource.supports[:remount] raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :remount" else if @current_resource.mounted converge_by("remount #{@current_resource.device}") do status = remount_fs() if status Chef::Log.info("#{@new_resource} remounted") end end else Chef::Log.debug("#{@new_resource} not mounted, nothing to remount") end end end def action_enable unless @current_resource.enabled && mount_options_unchanged? converge_by("remount #{@current_resource.device}") do status = enable_fs if status Chef::Log.info("#{@new_resource} enabled") else Chef::Log.debug("#{@new_resource} already enabled") end end end end def action_disable if @current_resource.enabled converge_by("remount #{@current_resource.device}") do status = disable_fs if status Chef::Log.info("#{@new_resource} disabled") else Chef::Log.debug("#{@new_resource} already disabled") end end end end def mount_fs raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :mount" end def umount_fs raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :umount" end def remount_fs raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :remount" end def enable_fs raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :enable" end def disable_fs raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :disable" end end end end chef-11.8.2/lib/chef/provider/file/0000755000004100000410000000000012254362222016764 5ustar www-datawww-datachef-11.8.2/lib/chef/provider/file/content.rb0000644000004100000410000000232112254362222020761 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/file_content_management/content_base' require 'chef/file_content_management/tempfile' class Chef class Provider class File class Content < Chef::FileContentManagement::ContentBase def file_for_provider if @new_resource.content tempfile = Chef::FileContentManagement::Tempfile.new(@new_resource).tempfile tempfile.write(@new_resource.content) tempfile.close tempfile else nil end end end end end end chef-11.8.2/lib/chef/provider/erl_call.rb0000644000004100000410000000562212254362222020154 0ustar www-datawww-data# # Author:: Joe Williams () # Copyright:: Copyright (c) 2009 Joe Williams # License:: Apache License, Version 2.0 # # 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. # require 'chef/log' require 'chef/mixin/command' require 'chef/provider' class Chef class Provider class ErlCall < Chef::Provider include Chef::Mixin::Command def initialize(node, new_resource) super(node, new_resource) end def whyrun_supported? true end def load_current_resource true end def action_run case @new_resource.name_type when "sname" node = "-sname #{@new_resource.node_name}" when "name" node = "-name #{@new_resource.node_name}" end if @new_resource.cookie cookie = "-c #{@new_resource.cookie}" else cookie = "" end if @new_resource.distributed distributed = "-s" else distributed = "" end command = "erl_call -e #{distributed} #{node} #{cookie}" converge_by("run erlang block") do begin pid, stdin, stdout, stderr = popen4(command, :waitlast => true) Chef::Log.debug("#{@new_resource} running") Chef::Log.debug("#{@new_resource} command: #{command}") Chef::Log.debug("#{@new_resource} code: #{@new_resource.code}") @new_resource.code.each_line { |line| stdin.puts(line.chomp) } stdin.close Chef::Log.debug("#{@new_resource} output: ") stdout_output = "" stdout.each_line { |line| stdout_output << line } stdout.close stderr_output = "" stderr.each_line { |line| stderr_output << line } stderr.close # fail if stderr contains anything if stderr_output.length > 0 raise Chef::Exceptions::ErlCall, stderr_output end # fail if the first 4 characters aren't "{ok," unless stdout_output[0..3].include?('{ok,') raise Chef::Exceptions::ErlCall, stdout_output end @new_resource.updated_by_last_action(true) Chef::Log.debug("#{@new_resource} #{stdout_output}") Chef::Log.info("#{@new_resouce} ran successfully") ensure Process.wait(pid) if pid end end end end end end chef-11.8.2/lib/chef/provider/group/0000755000004100000410000000000012254362222017201 5ustar www-datawww-datachef-11.8.2/lib/chef/provider/group/gpasswd.rb0000644000004100000410000000465012254362222021203 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/group/groupadd' require 'chef/mixin/shell_out' class Chef class Provider class Group class Gpasswd < Chef::Provider::Group::Groupadd include Chef::Mixin::ShellOut def load_current_resource super end def define_resource_requirements super requirements.assert(:all_actions) do |a| a.assertion { ::File.exists?("/usr/bin/gpasswd") } a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/bin/gpasswd for #{@new_resource}" # No whyrun alternative: this component should be available in the base install of any given system that uses it end end def modify_group_members if(@new_resource.append) unless @new_resource.members.empty? @new_resource.members.each do |member| Chef::Log.debug("#{@new_resource} appending member #{member} to group #{@new_resource.group_name}") shell_out!("gpasswd -a #{member} #{@new_resource.group_name}") end else Chef::Log.debug("#{@new_resource} not changing group members, the group has no members to add") end else unless @new_resource.members.empty? Chef::Log.debug("#{@new_resource} setting group members to #{@new_resource.members.join(', ')}") shell_out!("gpasswd -M #{@new_resource.members.join(',')} #{@new_resource.group_name}") else Chef::Log.debug("#{@new_resource} setting group members to: none") shell_out!("gpasswd -M \"\" #{@new_resource.group_name}") end end end end end end end chef-11.8.2/lib/chef/provider/group/pw.rb0000644000004100000410000000641012254362222020155 0ustar www-datawww-data# # Author:: Stephen Haynes () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Provider class Group class Pw < Chef::Provider::Group def load_current_resource super end def define_resource_requirements super requirements.assert(:all_actions) do |a| a.assertion { ::File.exists?("/usr/sbin/pw") } a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/pw for #{@new_resource}" # No whyrun alternative: this component should be available in the base install of any given system that uses it end end # Create the group def create_group command = "pw groupadd" command << set_options command << set_members_option run_command(:command => command) end # Manage the group when it already exists def manage_group command = "pw groupmod" command << set_options command << set_members_option run_command(:command => command) end # Remove the group def remove_group run_command(:command => "pw groupdel #{@new_resource.group_name}") end # Little bit of magic as per Adam's useradd provider to pull and assign the command line flags # # ==== Returns # :: A string containing the option and then the quoted value def set_options opts = " #{@new_resource.group_name}" if @new_resource.gid && (@current_resource.gid != @new_resource.gid) Chef::Log.debug("#{@new_resource}: current gid (#{@current_resource.gid}) doesnt match target gid (#{@new_resource.gid}), changing it") opts << " -g '#{@new_resource.gid}'" end opts end # Set the membership option depending on the current resource states def set_members_option opt = "" unless @new_resource.members.empty? opt << " -M #{@new_resource.members.join(',')}" Chef::Log.debug("#{@new_resource} setting group members to #{@new_resource.members.join(', ')}") else # New member list is empty so we should delete any old group members unless @current_resource.members.empty? opt << " -d #{@current_resource.members.join(',')}" Chef::Log.debug("#{@new_resource} removing group members #{@current_resource.members.join(', ')}") else Chef::Log.debug("#{@new_resource} not changing group members, the group has no members") end end opt end end end end end chef-11.8.2/lib/chef/provider/group/usermod.rb0000644000004100000410000000473412254362222021214 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/group/groupadd' class Chef class Provider class Group class Usermod < Chef::Provider::Group::Groupadd def load_current_resource super end def define_resource_requirements super requirements.assert(:all_actions) do |a| a.assertion { ::File.exists?("/usr/sbin/usermod") } a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/usermod for #{@new_resource}" # No whyrun alternative: this component should be available in the base install of any given system that uses it end requirements.assert(:modify, :create) do |a| a.assertion { @new_resource.members.empty? || @new_resource.append } a.failure_message Chef::Exceptions::Group, "setting group members directly is not supported by #{self.to_s}, must set append true in group" # No whyrun alternative - this action is simply not supported. end end def modify_group_members case node[:platform] when "openbsd", "netbsd", "aix", "solaris2", "smartos" append_flags = "-G" when "solaris", "suse", "opensuse" append_flags = "-a -G" end unless @new_resource.members.empty? if(@new_resource.append) @new_resource.members.each do |member| Chef::Log.debug("#{@new_resource} appending member #{member} to group #{@new_resource.group_name}") run_command(:command => "usermod #{append_flags} #{@new_resource.group_name} #{member}" ) end end else Chef::Log.debug("#{@new_resource} not changing group members, the group has no members") end end end end end end chef-11.8.2/lib/chef/provider/group/groupmod.rb0000644000004100000410000001025412254362222021364 0ustar www-datawww-data# # Author:: Dan Crosta () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/mixin/shell_out' class Chef class Provider class Group class Groupmod < Chef::Provider::Group include Chef::Mixin::ShellOut def load_current_resource super [ "group", "user" ].each do |binary| raise Chef::Exceptions::Group, "Could not find binary /usr/sbin/#{binary} for #{@new_resource}" unless ::File.exists?("/usr/sbin/#{binary}") end end # Create the group def create_group command = "group add" command << set_options shell_out!(command) add_group_members(@new_resource.members) end # Manage the group when it already exists def manage_group if @new_resource.append to_add = @new_resource.members.dup to_add.reject! { |user| @current_resource.members.include?(user) } to_delete = Array.new Chef::Log.debug("#{@new_resource} not changing group members, the group has no members to add") if to_add.empty? else to_add = @new_resource.members.dup to_add.reject! { |user| @current_resource.members.include?(user) } to_delete = @current_resource.members.dup to_delete.reject! { |user| @new_resource.members.include?(user) } Chef::Log.debug("#{@new_resource} setting group members to: none") if @new_resource.members.empty? end if to_delete.empty? # If we are only adding new members to this group, then # call add_group_members with only those users add_group_members(to_add) else Chef::Log.debug("#{@new_resource} removing members #{to_delete.join(', ')}") # This is tricky, but works: rename the existing group to # "_bak", create a new group with the same GID and # "", then set correct members on that group rename = "group mod -n #{@new_resource.group_name}_bak #{@new_resource.group_name}" shell_out!(rename) create = "group add" create << set_options(:overwrite_gid => true) shell_out!(create) # Ignore to_add here, since we're replacing the group we # have to add all members who should be in the group. add_group_members(@new_resource.members) remove = "group del #{@new_resource.group_name}_bak" shell_out!(remove) end end # Remove the group def remove_group shell_out!("group del #{@new_resource.group_name}") end # Adds a list of usernames to the group using `user mod` def add_group_members(members) Chef::Log.debug("#{@new_resource} adding members #{members.join(', ')}") if !members.empty? members.each do |user| shell_out!("user mod -G #{@new_resource.group_name} #{user}") end end # Little bit of magic as per Adam's useradd provider to pull and assign the command line flags # # ==== Returns # :: A string containing the option and then the quoted value def set_options(overwrite_gid=false) opts = "" if overwrite_gid || @new_resource.gid && (@current_resource.gid != @new_resource.gid) opts << " -g '#{@new_resource.gid}'" end if overwrite_gid opts << " -o" end opts << " #{@new_resource.group_name}" opts end end end end end chef-11.8.2/lib/chef/provider/group/dscl.rb0000644000004100000410000001151312254362222020454 0ustar www-datawww-data# # Author:: Dreamcat4 () # Copyright:: Copyright (c) 2009 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Provider class Group class Dscl < Chef::Provider::Group def dscl(*args) host = "." stdout_result = ""; stderr_result = ""; cmd = "dscl #{host} -#{args.join(' ')}" status = popen4(cmd) do |pid, stdin, stdout, stderr| stdout.each { |line| stdout_result << line } stderr.each { |line| stderr_result << line } end return [cmd, status, stdout_result, stderr_result] end def safe_dscl(*args) result = dscl(*args) return "" if ( args.first =~ /^delete/ ) && ( result[1].exitstatus != 0 ) raise(Chef::Exceptions::Group,"dscl error: #{result.inspect}") unless result[1].exitstatus == 0 raise(Chef::Exceptions::Group,"dscl error: #{result.inspect}") if result[2] =~ /No such key: / return result[2] end # This is handled in providers/group.rb by Etc.getgrnam() # def group_exists?(group) # groups = safe_dscl("list /Groups") # !! ( groups =~ Regexp.new("\n#{group}\n") ) # end # get a free GID greater than 200 def get_free_gid(search_limit=1000) gid = nil; next_gid_guess = 200 groups_gids = safe_dscl("list /Groups gid") while(next_gid_guess < search_limit + 200) if groups_gids =~ Regexp.new("#{Regexp.escape(next_gid_guess.to_s)}\n") next_gid_guess += 1 else gid = next_gid_guess break end end return gid || raise("gid not found. Exhausted. Searched #{search_limit} times") end def gid_used?(gid) return false unless gid groups_gids = safe_dscl("list /Groups gid") !! ( groups_gids =~ Regexp.new("#{Regexp.escape(gid.to_s)}\n") ) end def set_gid @new_resource.gid(get_free_gid) if [nil,""].include? @new_resource.gid raise(Chef::Exceptions::Group,"gid is already in use") if gid_used?(@new_resource.gid) safe_dscl("create /Groups/#{@new_resource.group_name} PrimaryGroupID #{@new_resource.gid}") end def set_members unless @new_resource.append Chef::Log.debug("#{@new_resource} removing group members #{@current_resource.members.join(' ')}") unless @current_resource.members.empty? safe_dscl("create /Groups/#{@new_resource.group_name} GroupMembers ''") # clear guid list safe_dscl("create /Groups/#{@new_resource.group_name} GroupMembership ''") # clear user list end unless @new_resource.members.empty? Chef::Log.debug("#{@new_resource} setting group members #{@new_resource.members.join(', ')}") safe_dscl("append /Groups/#{@new_resource.group_name} GroupMembership #{@new_resource.members.join(' ')}") end end def define_resource_requirements super requirements.assert(:all_actions) do |a| a.assertion { ::File.exists?("/usr/bin/dscl") } a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/bin/dscl for #{@new_resource.name}" # No whyrun alternative: this component should be available in the base install of any given system that uses it end end def load_current_resource super end def create_group dscl_create_group set_gid set_members end def manage_group if @new_resource.group_name && (@current_resource.group_name != @new_resource.group_name) dscl_create_group end if @new_resource.gid && (@current_resource.gid != @new_resource.gid) set_gid end if @new_resource.members && (@current_resource.members != @new_resource.members) set_members end end def dscl_create_group safe_dscl("create /Groups/#{@new_resource.group_name}") safe_dscl("create /Groups/#{@new_resource.group_name} Password '*'") end def remove_group safe_dscl("delete /Groups/#{@new_resource.group_name}") end end end end end chef-11.8.2/lib/chef/provider/group/aix.rb0000644000004100000410000000414512254362222020313 0ustar www-datawww-data# # Author:: Doug MacEachern () # Copyright:: Copyright (c) 2010 VMware, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/group/usermod' class Chef class Provider class Group class Aix < Chef::Provider::Group::Usermod def required_binaries [ "/usr/bin/mkgroup", "/usr/bin/chgroup", "/usr/sbin/rmgroup" ] end def create_group command = "mkgroup" command << set_options << " #{@new_resource.group_name}" run_command(:command => command) modify_group_members end def manage_group command = "chgroup" options = set_options #Usage: chgroup [-R load_module] "attr=value" ... group if options.size > 0 command << options << " #{@new_resource.group_name}" run_command(:command => command) end modify_group_members end def remove_group run_command(:command => "rmgroup #{@new_resource.group_name}") end def set_options opts = "" { :gid => "id" }.sort { |a,b| a[0] <=> b[0] }.each do |field, option| if @current_resource.send(field) != @new_resource.send(field) if @new_resource.send(field) Chef::Log.debug("#{@new_resource} setting #{field.to_s} to #{@new_resource.send(field)}") opts << " '#{option}=#{@new_resource.send(field)}'" end end end opts end end end end end chef-11.8.2/lib/chef/provider/group/groupadd.rb0000644000004100000410000000616412254362222021342 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Provider class Group class Groupadd < Chef::Provider::Group def required_binaries [ "/usr/sbin/groupadd", "/usr/sbin/groupmod", "/usr/sbin/groupdel" ] end def load_current_resource super end def define_resource_requirements super required_binaries.each do |required_binary| requirements.assert(:all_actions) do |a| a.assertion { ::File.exists?(required_binary) } a.failure_message Chef::Exceptions::Group, "Could not find binary #{required_binary} for #{@new_resource}" # No whyrun alternative: this component should be available in the base install of any given system that uses it end end end # Create the group def create_group command = "groupadd" command << set_options command << groupadd_options run_command(:command => command) modify_group_members end # Manage the group when it already exists def manage_group command = "groupmod" command << set_options run_command(:command => command) modify_group_members end # Remove the group def remove_group run_command(:command => "groupdel #{@new_resource.group_name}") end def modify_group_members raise Chef::Exceptions::Group, "you must override modify_group_members in #{self.to_s}" end # Little bit of magic as per Adam's useradd provider to pull the assign the command line flags # # ==== Returns # :: A string containing the option and then the quoted value def set_options opts = "" { :gid => "-g" }.sort { |a,b| a[0] <=> b[0] }.each do |field, option| if @current_resource.send(field) != @new_resource.send(field) if @new_resource.send(field) opts << " #{option} '#{@new_resource.send(field)}'" Chef::Log.debug("#{@new_resource} set #{field.to_s} to #{@new_resource.send(field)}") end end end opts << " #{@new_resource.group_name}" end def groupadd_options opts = '' opts << " -r" if @new_resource.system opts << " -o" if @new_resource.non_unique opts end end end end end chef-11.8.2/lib/chef/provider/group/windows.rb0000644000004100000410000000433412254362222021224 0ustar www-datawww-data# # Author:: Doug MacEachern () # Copyright:: Copyright (c) 2010 VMware, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/user' if RUBY_PLATFORM =~ /mswin|mingw32|windows/ require 'chef/util/windows/net_group' end class Chef class Provider class Group class Windows < Chef::Provider::Group def initialize(new_resource,run_context) super @net_group = Chef::Util::Windows::NetGroup.new(@new_resource.group_name) end def load_current_resource @current_resource = Chef::Resource::Group.new(@new_resource.name) @current_resource.group_name(@new_resource.group_name) members = nil begin members = @net_group.local_get_members rescue => e @group_exists = false Chef::Log.debug("#{@new_resource} group does not exist") end if members @current_resource.members(members) end @current_resource end def create_group @net_group.local_add manage_group end def manage_group if @new_resource.append begin #ERROR_MEMBER_IN_ALIAS if a member already exists in the group @net_group.local_add_members(@new_resource.members) rescue members = @new_resource.members + @current_resource.members @net_group.local_set_members(members.uniq) end else @net_group.local_set_members(@new_resource.members) end end def remove_group @net_group.local_delete end end end end end chef-11.8.2/lib/chef/provider/group/suse.rb0000644000004100000410000000423112254362222020505 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/group/groupadd' require 'chef/mixin/shell_out' class Chef class Provider class Group class Suse < Chef::Provider::Group::Groupadd include Chef::Mixin::ShellOut def load_current_resource super end def define_resource_requirements super requirements.assert(:all_actions) do |a| a.assertion { ::File.exists?("/usr/sbin/groupmod") } a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/groupmod for #{@new_resource.name}" # No whyrun alternative: this component should be available in the base install of any given system that uses it end end def modify_group_members unless @new_resource.members.empty? if(@new_resource.append) @new_resource.members.each do |member| Chef::Log.debug("#{@new_resource} appending member #{member} to group #{@new_resource.group_name}") shell_out!("groupmod -A #{member} #{@new_resource.group_name}") end else Chef::Log.debug("#{@new_resource} setting group members to #{@new_resource.members.join(', ')}") shell_out!("groupmod -A #{@new_resource.members.join(',')} #{@new_resource.group_name}") end else Chef::Log.debug("#{@new_resource} not changing group members, the group has no members") end end end end end end chef-11.8.2/lib/chef/provider/ifconfig/0000755000004100000410000000000012254362222017631 5ustar www-datawww-datachef-11.8.2/lib/chef/provider/ifconfig/redhat.rb0000644000004100000410000000355312254362222021433 0ustar www-datawww-data# # Author:: Xabier de Zuazo (xabier@onddo.com) # Copyright:: Copyright (c) 2013 Onddo Labs, SL. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/ifconfig' class Chef class Provider class Ifconfig class Redhat < Chef::Provider::Ifconfig def initialize(new_resource, run_context) super(new_resource, run_context) @config_template = %{ <% if @new_resource.device %>DEVICE=<%= @new_resource.device %><% end %> <% if @new_resource.onboot == "yes" %>ONBOOT=<%= @new_resource.onboot %><% end %> <% if @new_resource.bootproto %>BOOTPROTO=<%= @new_resource.bootproto %><% end %> <% if @new_resource.target %>IPADDR=<%= @new_resource.target %><% end %> <% if @new_resource.mask %>NETMASK=<%= @new_resource.mask %><% end %> <% if @new_resource.network %>NETWORK=<%= @new_resource.network %><% end %> <% if @new_resource.bcast %>BROADCAST=<%= @new_resource.bcast %><% end %> <% if @new_resource.onparent %>ONPARENT=<%= @new_resource.onparent %><% end %> <% if @new_resource.hwaddr %>HWADDR=<%= @new_resource.hwaddr %><% end %> <% if @new_resource.metric %>METRIC=<%= @new_resource.metric %><% end %> <% if @new_resource.mtu %>MTU=<%= @new_resource.mtu %><% end %> } @config_path = "/etc/sysconfig/network-scripts/ifcfg-#{@new_resource.device}" end end end end end chef-11.8.2/lib/chef/provider/ifconfig/debian.rb0000644000004100000410000000501612254362222021402 0ustar www-datawww-data# # Author:: Xabier de Zuazo (xabier@onddo.com) # Copyright:: Copyright (c) 2013 Onddo Labs, SL. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/ifconfig' require 'chef/util/file_edit' class Chef class Provider class Ifconfig class Debian < Chef::Provider::Ifconfig def initialize(new_resource, run_context) super(new_resource, run_context) @config_template = %{ <% if @new_resource.device %> <% if @new_resource.onboot == "yes" %>auto <%= @new_resource.device %><% end %> <% case @new_resource.bootproto when "dhcp" %> iface <%= @new_resource.device %> inet dhcp <% when "bootp" %> iface <%= @new_resource.device %> inet bootp <% else %> iface <%= @new_resource.device %> inet static <% if @new_resource.target %>address <%= @new_resource.target %><% end %> <% if @new_resource.mask %>netmask <%= @new_resource.mask %><% end %> <% if @new_resource.network %>network <%= @new_resource.network %><% end %> <% if @new_resource.bcast %>broadcast <%= @new_resource.bcast %><% end %> <% if @new_resource.metric %>metric <%= @new_resource.metric %><% end %> <% if @new_resource.hwaddr %>hwaddress <%= @new_resource.hwaddr %><% end %> <% if @new_resource.mtu %>mtu <%= @new_resource.mtu %><% end %> <% end %> <% end %> } @config_path = "/etc/network/interfaces.d/ifcfg-#{@new_resource.device}" end def generate_config check_interfaces_config super end protected def check_interfaces_config converge_by ('modify configuration file : /etc/network/interfaces') do Dir.mkdir('/etc/network/interfaces.d') unless ::File.directory?('/etc/network/interfaces.d') conf = Chef::Util::FileEdit.new('/etc/network/interfaces') conf.insert_line_if_no_match('^\s*source\s+/etc/network/interfaces[.]d/[*]\s*$', 'source /etc/network/interfaces.d/*') conf.write_file end end end end end end chef-11.8.2/lib/chef/provider/ifconfig/aix.rb0000644000004100000410000000705512254362222020746 0ustar www-datawww-data# # Author:: Kaustubh Deorukhkar (kaustubh@clogeny.com) # Copyright:: Copyright (c) 2013 Opscode, Inc # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/ifconfig' class Chef class Provider class Ifconfig class Aix < Chef::Provider::Ifconfig def load_current_resource @current_resource = Chef::Resource::Ifconfig.new(@new_resource.name) @interface_exists = false found_interface = false interface = {} @status = popen4("ifconfig -a") do |pid, stdin, stdout, stderr| stdout.each do |line| if !found_interface if line =~ /^(\S+):\sflags=(\S+)/ # We have interface name, if this is the interface for @current_resource, load info else skip till next interface is found. if $1 == @new_resource.device # Found interface found_interface = true @interface_exists = true @current_resource.target(@new_resource.target) @current_resource.device($1) interface[:flags] = $2 @current_resource.metric($1) if line =~ /metric\s(\S+)/ end end else # parse interface related information, stop when next interface is found. if line =~ /^(\S+):\sflags=(\S+)/ # we are done parsing interface info and hit another one, so stop. found_interface = false break else if found_interface # read up interface info @current_resource.inet_addr($1) if line =~ /inet\s(\S+)\s/ @current_resource.bcast($1) if line =~ /broadcast\s(\S+)/ @current_resource.mask(hex_to_dec_netmask($1)) if line =~ /netmask\s(\S+)\s/ end end end end end @current_resource end private def add_command # ifconfig changes are temporary, chdev persist across reboots. raise Chef::Exceptions::Ifconfig, "interface metric attribute cannot be set for :add action" if @new_resource.metric command = "chdev -l #{@new_resource.device} -a netaddr=#{@new_resource.name}" command << " -a netmask=#{@new_resource.mask}" if @new_resource.mask command << " -a mtu=#{@new_resource.mtu}" if @new_resource.mtu command end def delete_command # ifconfig changes are temporary, chdev persist across reboots. "chdev -l #{@new_resource.device} -a state=down" end def loopback_device "lo0" end def hex_to_dec_netmask(netmask) # example '0xffff0000' -> '255.255.0.0' dec = netmask[2..3].to_i(16).to_s(10) [4,6,8].each { |n| dec = dec + "." + netmask[n..n+1].to_i(16).to_s(10) } dec end end end end end chef-11.8.2/lib/chef/provider/lwrp_base.rb0000644000004100000410000001366112254362222020357 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Walters () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008-2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider' class Chef class Provider # == Chef::Provider::LWRPBase # Base class from which LWRP providers inherit. class LWRPBase < Provider # Chef::Provider::LWRPBase::InlineResources # Implementation of inline resource convergence for LWRP providers. See # Provider::LWRPBase.use_inline_resources for a longer explanation. # # This code is restricted to a module so that it can be selectively # applied to providers on an opt-in basis. module InlineResources # Class methods for InlineResources. Overrides the `action` DSL method # with one that enables inline resource convergence. module ClassMethods # Defines an action method on the provider, using # recipe_eval_with_update_check to execute the given block. def action(name, &block) define_method("action_#{name}") do recipe_eval_with_update_check(&block) end end end # Executes the given block in a temporary run_context with its own # resource collection. After the block is executed, any resources # declared inside are converged, and if any are updated, the # new_resource will be marked updated. def recipe_eval_with_update_check(&block) saved_run_context = @run_context temp_run_context = @run_context.dup @run_context = temp_run_context @run_context.resource_collection = Chef::ResourceCollection.new return_value = instance_eval(&block) Chef::Runner.new(@run_context).converge return_value ensure @run_context = saved_run_context if temp_run_context.resource_collection.any? {|r| r.updated? } new_resource.updated_by_last_action(true) end end end extend Chef::Mixin::ConvertToClassName extend Chef::Mixin::FromFile include Chef::DSL::Recipe # These were previously provided by Chef::Mixin::RecipeDefinitionDSLCore. # They are not included by its replacment, Chef::DSL::Recipe, but # they may be used in existing LWRPs. include Chef::DSL::PlatformIntrospection include Chef::DSL::DataQuery def self.build_from_file(cookbook_name, filename, run_context) provider_name = filename_to_qualified_string(cookbook_name, filename) # Add log entry if we override an existing light-weight provider. class_name = convert_to_class_name(provider_name) if Chef::Provider.const_defined?(class_name) Chef::Log.info("#{class_name} light-weight provider already initialized -- overriding!") end provider_class = Class.new(self) provider_class.class_from_file(filename) class_name = convert_to_class_name(provider_name) Chef::Provider.const_set(class_name, provider_class) Chef::Log.debug("Loaded contents of #{filename} into a provider named #{provider_name} defined in Chef::Provider::#{class_name}") provider_class end # Enables inline evaluation of resources in provider actions. # # Without this option, any resources declared inside the LWRP are added # to the resource collection after the current position at the time the # action is executed. Because they are added to the primary resource # collection for the chef run, they can notify other resources outside # the LWRP, and potentially be notified by resources outside the LWRP # (but this is complicated by the fact that they don't exist until the # provider executes). In this mode, it is impossible to correctly set the # updated_by_last_action flag on the parent LWRP resource, since it # executes and returns before its component resources are run. # # With this option enabled, each action creates a temporary run_context # with its own resource collection, evaluates the action's code in that # context, and then converges the resources created. If any resources # were updated, then this provider's new_resource will be marked updated. # # In this mode, resources created within the LWRP cannot interact with # external resources via notifies, though notifications to other # resources within the LWRP will work. Delayed notifications are executed # at the conclusion of the provider's action, *not* at the end of the # main chef run. # # This mode of evaluation is experimental, but is believed to be a better # set of tradeoffs than the append-after mode, so it will likely become # the default in a future major release of Chef. # def self.use_inline_resources extend InlineResources::ClassMethods include InlineResources end # DSL for defining a provider's actions. def self.action(name, &block) define_method("action_#{name}") do instance_eval(&block) end end # no-op `load_current_resource`. Allows simple LWRP providers to work # without defining this method explicitly (silences # Chef::Exceptions::Override exception) def load_current_resource end end end end chef-11.8.2/lib/chef/provider/ohai.rb0000644000004100000410000000243112254362222017312 0ustar www-datawww-data# # Author:: Michael Leianrtas () # Copyright:: Copyright (c) 2010 Michael Leinartas # License:: Apache License, Version 2.0 # # 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. # require 'ohai' class Chef class Provider class Ohai < Chef::Provider def whyrun_supported? true end def load_current_resource true end def action_reload converge_by("re-run ohai and merge results into node attributes") do ohai = ::Ohai::System.new if @new_resource.plugin ohai.require_plugin @new_resource.plugin else ohai.all_plugins end node.automatic_attrs.merge! ohai.data Chef::Log.info("#{@new_resource} reloaded") end end end end end chef-11.8.2/lib/chef/provider/registry_key.rb0000644000004100000410000001334012254362222021113 0ustar www-datawww-data# # Author:: Prajakta Purohit () # Author:: Lamont Granquist () # # Copyright:: 2011, 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. # require 'chef/config' require 'chef/log' require 'chef/resource/file' require 'chef/mixin/checksum' require 'chef/provider' require 'etc' require 'fileutils' require 'chef/scan_access_control' require 'chef/mixin/shell_out' require 'chef/win32/registry' class Chef class Provider class RegistryKey < Chef::Provider include Chef::Mixin::Checksum include Chef::Mixin::ShellOut def whyrun_supported? true end def running_on_windows! unless Chef::Platform.windows? raise Chef::Exceptions::Win32NotWindows, "Attempt to manipulate the windows registry on a non-windows node" end end def load_current_resource running_on_windows! @current_resource ||= Chef::Resource::RegistryKey.new(@new_resource.key, run_context) @current_resource.key(@new_resource.key) @current_resource.architecture(@new_resource.architecture) @current_resource.recursive(@new_resource.recursive) if registry.key_exists?(@new_resource.key) @current_resource.values(registry.get_values(@new_resource.key)) end values_to_hash(@current_resource.values) @current_resource end def registry @registry ||= Chef::Win32::Registry.new(@run_context, @new_resource.architecture) end def values_to_hash(values) if values @name_hash = Hash[values.map { |val| [val[:name], val] }] else @name_hash = {} end end def define_resource_requirements requirements.assert(:create, :create_if_missing, :delete, :delete_key) do |a| a.assertion{ registry.hive_exists?(@new_resource.key) } a.failure_message(Chef::Exceptions::Win32RegHiveMissing, "Hive #{@new_resource.key.split("\\").shift} does not exist") end requirements.assert(:create) do |a| a.assertion{ registry.key_exists?(@new_resource.key) } a.whyrun("Key #{@new_resource.key} does not exist. Unless it would have been created before, attempt to modify its values would fail.") end requirements.assert(:create, :create_if_missing) do |a| #If keys missing in the path and recursive == false a.assertion{ !registry.keys_missing?(@current_resource.key) || @new_resource.recursive } a.failure_message(Chef::Exceptions::Win32RegNoRecursive, "Intermediate keys missing but recursive is set to false") a.whyrun("Intermediate keys in #{@new_resource.key} go not exist. Unless they would have been created earlier, attempt to modify them would fail.") end requirements.assert(:delete_key) do |a| #If key to be deleted has subkeys but recurssive == false a.assertion{ !registry.key_exists?(@new_resource.key) || !registry.has_subkeys?(@new_resource.key) || @new_resource.recursive } a.failure_message(Chef::Exceptions::Win32RegNoRecursive, "#{@new_resource.key} has subkeys but recursive is set to false.") a.whyrun("#{@current_resource.key} has subkeys, but recursive is set to false. attempt to delete would fails unless subkeys were deleted prior to this action.") end end def action_create unless registry.key_exists?(@current_resource.key) converge_by("create key #{@new_resource.key}") do registry.create_key(@new_resource.key, @new_resource.recursive) end end @new_resource.values.each do |value| if @name_hash.has_key?(value[:name]) current_value = @name_hash[value[:name]] unless current_value[:type] == value[:type] && current_value[:data] == value[:data] converge_by("set value #{value}") do registry.set_value(@new_resource.key, value) end end else converge_by("set value #{value}") do registry.set_value(@new_resource.key, value) end end end end def action_create_if_missing unless registry.key_exists?(@new_resource.key) converge_by("create key #{@new_resource.key}") do registry.create_key(@new_resource.key, @new_resource.recursive) end end @new_resource.values.each do |value| unless @name_hash.has_key?(value[:name]) converge_by("create value #{value}") do registry.set_value(@new_resource.key, value) end end end end def action_delete if registry.key_exists?(@new_resource.key) @new_resource.values.each do |value| if @name_hash.has_key?(value[:name]) converge_by("delete value #{value}") do registry.delete_value(@new_resource.key, value) end end end end end def action_delete_key if registry.key_exists?(@new_resource.key) converge_by("delete key #{@new_resource.key}") do registry.delete_key(@new_resource.key, @new_resource.recursive) end end end end end end chef-11.8.2/lib/chef/provider/link.rb0000644000004100000410000001210612254362222017327 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/config' require 'chef/log' require 'chef/mixin/shell_out' require 'chef/mixin/file_class' require 'chef/resource/link' require 'chef/provider' require 'chef/scan_access_control' class Chef class Provider class Link < Chef::Provider include Chef::Mixin::EnforceOwnershipAndPermissions include Chef::Mixin::ShellOut include Chef::Mixin::FileClass def negative_complement(big) if big > 1073741823 # Fixnum max big -= (2**32) # diminished radix wrap to negative end big end private :negative_complement def whyrun_supported? true end def load_current_resource @current_resource = Chef::Resource::Link.new(@new_resource.name) @current_resource.target_file(@new_resource.target_file) if file_class.symlink?(@current_resource.target_file) @current_resource.link_type(:symbolic) @current_resource.to( canonicalize(file_class.readlink(@current_resource.target_file)) ) else @current_resource.link_type(:hard) if ::File.exists?(@current_resource.target_file) if ::File.exists?(@new_resource.to) && file_class.stat(@current_resource.target_file).ino == file_class.stat(@new_resource.to).ino @current_resource.to(canonicalize(@new_resource.to)) else @current_resource.to("") end end end ScanAccessControl.new(@new_resource, @current_resource).set_all! @current_resource end def define_resource_requirements requirements.assert(:delete) do |a| a.assertion do if @current_resource.to @current_resource.link_type == @new_resource.link_type and (@current_resource.link_type == :symbolic or @current_resource.to != '') else true end end a.failure_message Chef::Exceptions::Link, "Cannot delete #{@new_resource} at #{@new_resource.target_file}! Not a #{@new_resource.link_type.to_s} link." a.whyrun("Would assume the link at #{@new_resource.target_file} was previously created") end end def canonicalize(path) Chef::Platform.windows? ? path.gsub('/', '\\') : path end def action_create if @current_resource.to != canonicalize(@new_resource.to) || @current_resource.link_type != @new_resource.link_type if @current_resource.to # nil if target_file does not exist converge_by("unlink existing file at #{@new_resource.target_file}") do ::File.unlink(@new_resource.target_file) end end if @new_resource.link_type == :symbolic converge_by("create symlink at #{@new_resource.target_file} to #{@new_resource.to}") do file_class.symlink(canonicalize(@new_resource.to),@new_resource.target_file) Chef::Log.debug("#{@new_resource} created #{@new_resource.link_type} link from #{@new_resource.to} -> #{@new_resource.target_file}") Chef::Log.info("#{@new_resource} created") end elsif @new_resource.link_type == :hard converge_by("create hard link at #{@new_resource.target_file} to #{@new_resource.to}") do file_class.link(@new_resource.to, @new_resource.target_file) Chef::Log.debug("#{@new_resource} created #{@new_resource.link_type} link from #{@new_resource.to} -> #{@new_resource.target_file}") Chef::Log.info("#{@new_resource} created") end end end if @new_resource.link_type == :symbolic if access_controls.requires_changes? converge_by(access_controls.describe_changes) do access_controls.set_all end end end end def action_delete if @current_resource.to # Exists converge_by("delete link at #{@new_resource.target_file}") do ::File.delete(@new_resource.target_file) Chef::Log.info("#{@new_resource} deleted") end end end # Implementation components *should not* follow symlinks when managing # access control (e.g., use lchmod instead of chmod) if the resource is a # symlink. def manage_symlink_access? @new_resource.link_type == :symbolic end end end end chef-11.8.2/lib/chef/provider/windows_script.rb0000644000004100000410000000427112254362222021454 0ustar www-datawww-data# # Author:: Adam Edwards () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/script' require 'chef/mixin/windows_architecture_helper' class Chef class Provider class WindowsScript < Chef::Provider::Script protected include Chef::Mixin::WindowsArchitectureHelper def initialize( new_resource, run_context, script_extension='') super( new_resource, run_context ) @script_extension = script_extension target_architecture = new_resource.architecture.nil? ? node_windows_architecture(run_context.node) : new_resource.architecture @is_wow64 = wow64_architecture_override_required?(run_context.node, target_architecture) if ( target_architecture == :i386 ) && ! is_i386_windows_process? raise Chef::Exceptions::Win32ArchitectureIncorrect, "Support for the i386 architecture from a 64-bit Ruby runtime is not yet implemented" end end public def action_run wow64_redirection_state = nil if @is_wow64 wow64_redirection_state = disable_wow64_file_redirection(@run_context.node) end begin super rescue raise ensure if ! wow64_redirection_state.nil? restore_wow64_file_redirection(@run_context.node, wow64_redirection_state) end end end def script_file base_script_name = "chef-script" temp_file_arguments = [ base_script_name, @script_extension ] @script_file ||= Tempfile.open(temp_file_arguments) end end end end chef-11.8.2/lib/chef/provider/template/0000755000004100000410000000000012254362222017660 5ustar www-datawww-datachef-11.8.2/lib/chef/provider/template/content.rb0000644000004100000410000000353112254362222021661 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/mixin/template' require 'chef/file_content_management/content_base' class Chef class Provider class Template class Content < Chef::FileContentManagement::ContentBase include Chef::Mixin::Template def template_location @template_file_cache_location ||= begin template_finder.find(@new_resource.source, :local => @new_resource.local, :cookbook => @new_resource.cookbook) end end private def file_for_provider context = TemplateContext.new(@new_resource.variables) context[:node] = @run_context.node context[:template_finder] = template_finder context._extend_modules(@new_resource.helper_modules) output = context.render_template(template_location) tempfile = Tempfile.open("chef-rendered-template") tempfile.binmode tempfile.write(output) tempfile.close tempfile end def template_finder @template_finder ||= begin TemplateFinder.new(run_context, @new_resource.cookbook_name, @run_context.node) end end end end end end chef-11.8.2/lib/chef/provider/remote_file/0000755000004100000410000000000012254362222020337 5ustar www-datawww-datachef-11.8.2/lib/chef/provider/remote_file/cache_control_data.rb0000644000004100000410000001313112254362222024457 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Author:: Jesse Campbell () # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Jesse Campbell # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'stringio' require 'chef/file_cache' require 'chef/json_compat' require 'chef/digester' require 'chef/exceptions' class Chef class Provider class RemoteFile # == CacheControlData # Implements per-uri storage of cache control data for a remote resource # along with a sanity check checksum of the file in question. # Provider::RemoteFile protocol implementation classes can use this # information to avoid re-fetching files when the current copy is up to # date. The way this information is used is protocol-dependent. For HTTP, # this information is sent to the origin server via headers to make a # conditional GET request. # # == API # The general shape of the API is active-record-the-pattern-like. New # instances should be instantiated via # `CacheControlData.load_and_validate`, which will do a find-or-create # operation and then sanity check the data against the checksum of the # current copy of the file. If there is no data or the sanity check # fails, the `etag` and `mtime` attributes will be set to nil; otherwise # they are populated with the previously saved values. # # After fetching a file, the CacheControlData instance should be updated # with new etag, mtime and checksum values in whatever format is # preferred by the protocol used. Then call #save to save the data to disk. class CacheControlData def self.load_and_validate(uri, current_copy_checksum) ccdata = new(uri) ccdata.load ccdata.validate!(current_copy_checksum) ccdata end # Entity Tag of the resource. HTTP-specific. See also: # http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.3.2 # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19 attr_accessor :etag # Last modified time of the remote resource. Different protocols will # use different types for this field (e.g., string representation of a # specific date format, integer, etc.) For HTTP-specific references, # see: # * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 # * http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.3.1 # * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25 attr_accessor :mtime # SHA2-256 Hash of the file as last fetched. attr_accessor :checksum # URI of the resource as a String. This is the "primary key" used for # storage and retrieval. attr_reader :uri def initialize(uri) uri = uri.dup uri.password = "XXXX" unless uri.userinfo.nil? @uri = uri.to_s end def load if previous_cc_data = load_data apply(previous_cc_data) self else false end end def validate!(current_copy_checksum) if current_copy_checksum.nil? or checksum != current_copy_checksum reset! false else true end end # Saves the data to disk using Chef::FileCache. The filename is a # sanitized version of the URI with a MD5 of the same URI appended (to # avoid collisions between different URIs having the same sanitized # form). def save Chef::FileCache.store("remote_file/#{sanitized_cache_file_basename}", json_data) end # :nodoc: # JSON representation of this object for storage. def json_data Chef::JSONCompat.to_json(hash_data) end private def hash_data as_hash = {} as_hash["etag"] = etag as_hash["mtime"] = mtime as_hash["checksum"] = checksum as_hash end def reset! @etag, @mtime = nil, nil end def apply(previous_cc_data) @etag = previous_cc_data["etag"] @mtime = previous_cc_data["mtime"] @checksum = previous_cc_data["checksum"] end def load_data Chef::JSONCompat.from_json(load_json_data) rescue Chef::Exceptions::FileNotFound, Yajl::ParseError false end def load_json_data Chef::FileCache.load("remote_file/#{sanitized_cache_file_basename}") end def sanitized_cache_file_basename # Scrub and truncate in accordance with the goals of keeping the name # human-readable but within the bounds of local file system # path length limits scrubbed_uri = uri.gsub(/\W/, '_')[0..63] uri_md5 = Chef::Digester.instance.generate_md5_checksum(StringIO.new(uri)) "#{scrubbed_uri}-#{uri_md5}.json" end end end end end chef-11.8.2/lib/chef/provider/remote_file/ftp.rb0000644000004100000410000001142712254362222021462 0ustar www-datawww-data# # Author:: Jesse Campbell () # Copyright:: Copyright (c) 2013 Jesse Campbell # License:: Apache License, Version 2.0 # # 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. # require 'uri' require 'tempfile' require 'net/ftp' require 'chef/provider/remote_file' require 'chef/file_content_management/tempfile' class Chef class Provider class RemoteFile class FTP attr_reader :uri attr_reader :new_resource attr_reader :current_resource def initialize(uri, new_resource, current_resource) @uri = uri @new_resource = new_resource @current_resource = current_resource validate_typecode! validate_path! end def hostname @uri.host end def port @uri.port end def use_passive_mode? ! new_resource.ftp_active_mode end def typecode uri.typecode end def user if uri.userinfo URI.unescape(uri.user) else 'anonymous' end end def pass if uri.userinfo URI.unescape(uri.password) else nil end end def directories parse_path if @directories.nil? @directories end def filename parse_path if @filename.nil? @filename end def fetch with_connection do get end end def ftp @ftp ||= Net::FTP.new end private def with_proxy_env saved_socks_env = ENV['SOCKS_SERVER'] ENV['SOCKS_SERVER'] = proxy_uri(@uri).to_s yield ensure ENV['SOCKS_SERVER'] = saved_socks_env end def with_connection with_proxy_env do connect yield end ensure disconnect end def validate_typecode! # Only support ascii and binary types if typecode and /\A[ai]\z/ !~ typecode raise ArgumentError, "invalid typecode: #{typecode.inspect}" end end def validate_path! parse_path end def connect # The access sequence is defined by RFC 1738 ftp.connect(hostname, port) ftp.passive = use_passive_mode? ftp.login(user, pass) directories.each do |cwd| ftp.voidcmd("CWD #{cwd}") end end def disconnect ftp.close end # Fetches using Net::FTP, returns a Tempfile with the content def get tempfile = Chef::FileContentManagement::Tempfile.new(@new_resource).tempfile if typecode ftp.voidcmd("TYPE #{typecode.upcase}") end ftp.getbinaryfile(filename, tempfile.path) tempfile.close if tempfile tempfile end #adapted from buildr/lib/buildr/core/transports.rb via chef/rest/rest_client.rb def proxy_uri(uri) proxy = Chef::Config["ftp_proxy"] proxy = URI.parse(proxy) if String === proxy if Chef::Config["ftp_proxy_user"] proxy.user = Chef::Config["ftp_proxy_user"] end if Chef::Config["ftp_proxy_pass"] proxy.password = Chef::Config["ftp_proxy_pass"] end excludes = Chef::Config[:no_proxy].to_s.split(/\s*,\s*/).compact excludes = excludes.map { |exclude| exclude =~ /:\d+$/ ? exclude : "#{exclude}:*" } return proxy unless excludes.any? { |exclude| File.fnmatch(exclude, "#{host}:#{port}") } end def parse_path path = uri.path.sub(%r{\A/}, '%2F') # re-encode the beginning slash because uri library decodes it. directories = path.split(%r{/}, -1) directories.each {|d| d.gsub!(/%([0-9A-Fa-f][0-9A-Fa-f])/) { [$1].pack("H2") } } unless filename = directories.pop raise ArgumentError, "no filename: #{path.inspect}" end if filename.length == 0 || filename.end_with?( "/" ) raise ArgumentError, "no filename: #{path.inspect}" end @directories, @filename = directories, filename end end end end end chef-11.8.2/lib/chef/provider/remote_file/local_file.rb0000644000004100000410000000262412254362222022761 0ustar www-datawww-data# # Author:: Jesse Campbell () # Copyright:: Copyright (c) 2013 Jesse Campbell # License:: Apache License, Version 2.0 # # 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. # require 'uri' require 'tempfile' require 'chef/provider/remote_file' class Chef class Provider class RemoteFile class LocalFile attr_reader :uri attr_reader :new_resource def initialize(uri, new_resource, current_resource) @new_resource = new_resource @uri = uri end # Fetches the file at uri, returning a Tempfile-like File handle def fetch tempfile = Chef::FileContentManagement::Tempfile.new(new_resource).tempfile Chef::Log.debug("#{new_resource} staging #{uri.path} to #{tempfile.path}") FileUtils.cp(uri.path, tempfile.path) tempfile.close if tempfile tempfile end end end end end chef-11.8.2/lib/chef/provider/remote_file/fetcher.rb0000644000004100000410000000257712254362222022317 0ustar www-datawww-data# # Author:: Jesse Campbell () # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Provider class RemoteFile class Fetcher def self.for_resource(uri, new_resource, current_resource) case uri.scheme when "http", "https" Chef::Provider::RemoteFile::HTTP.new(uri, new_resource, current_resource) when "ftp" Chef::Provider::RemoteFile::FTP.new(uri, new_resource, current_resource) when "file" Chef::Provider::RemoteFile::LocalFile.new(uri, new_resource, current_resource) else raise ArgumentError, "Invalid uri, Only http(s), ftp, and file are currently supported" end end end end end end chef-11.8.2/lib/chef/provider/remote_file/http.rb0000644000004100000410000000734512254362222021654 0ustar www-datawww-data# # Author:: Jesse Campbell () # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Jesse Campbell # License:: Apache License, Version 2.0 # # 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. # require 'chef/http/simple' require 'chef/digester' require 'chef/provider/remote_file' require 'chef/provider/remote_file/cache_control_data' class Chef class Provider class RemoteFile class HTTP attr_reader :uri attr_reader :new_resource attr_reader :current_resource # Parse the uri into instance variables def initialize(uri, new_resource, current_resource) @uri = uri @new_resource = new_resource @current_resource = current_resource end def headers conditional_get_headers.merge(new_resource.headers) end def conditional_get_headers cache_control_headers = {} if last_modified = cache_control_data.mtime and want_mtime_cache_control? cache_control_headers["if-modified-since"] = last_modified end if etag = cache_control_data.etag and want_etag_cache_control? cache_control_headers["if-none-match"] = etag end Chef::Log.debug("Cache control headers: #{cache_control_headers.inspect}") cache_control_headers end def fetch http = Chef::HTTP::Simple.new(uri, http_client_opts) tempfile = http.streaming_request(uri, headers) if tempfile update_cache_control_data(tempfile, http.last_response) tempfile.close end tempfile end private def update_cache_control_data(tempfile, response) cache_control_data.checksum = Chef::Digester.checksum_for_file(tempfile.path) cache_control_data.mtime = last_modified_time_from(response) cache_control_data.etag = etag_from(response) cache_control_data.save end def cache_control_data @cache_control_data ||= CacheControlData.load_and_validate(uri, current_resource.checksum) end def want_mtime_cache_control? new_resource.use_last_modified end def want_etag_cache_control? new_resource.use_etag end def last_modified_time_from(response) response['last_modified'] || response['date'] end def etag_from(response) response['etag'] end def http_client_opts opts={} # CHEF-3140 # 1. If it's already compressed, trying to compress it more will # probably be counter-productive. # 2. Some servers are misconfigured so that you GET $URL/file.tgz but # they respond with content type of tar and content encoding of gzip, # which tricks Chef::REST into decompressing the response body. In this # case you'd end up with a tar archive (no gzip) named, e.g., foo.tgz, # which is not what you wanted. if uri.to_s =~ /gz$/ Chef::Log.debug("turning gzip compression off due to filename ending in gz") opts[:disable_gzip] = true end opts end end end end end chef-11.8.2/lib/chef/provider/remote_file/content.rb0000644000004100000410000000515312254362222022342 0ustar www-datawww-data# # Author:: Jesse Campbell () # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'rest_client' require 'uri' require 'tempfile' require 'chef/file_content_management/content_base' class Chef class Provider class RemoteFile class Content < Chef::FileContentManagement::ContentBase private def file_for_provider Chef::Log.debug("#{@new_resource} checking for changes") if current_resource_matches_target_checksum? Chef::Log.debug("#{@new_resource} checksum matches target checksum (#{@new_resource.checksum}) - not updating") else sources = @new_resource.source raw_file = try_multiple_sources(sources) end raw_file end # Given an array of source uris, iterate through them until one does not fail def try_multiple_sources(sources) sources = sources.dup source = sources.shift begin uri = URI.parse(source) raw_file = grab_file_from_uri(uri) rescue SocketError, Errno::ECONNREFUSED, Errno::ENOENT, Errno::EACCES, Timeout::Error, Net::HTTPFatalError, Net::FTPError => e Chef::Log.warn("#{@new_resource} cannot be downloaded from #{source}: #{e.to_s}") if source = sources.shift Chef::Log.info("#{@new_resource} trying to download from another mirror") retry else raise e end end raw_file end # Given a source uri, return a Tempfile, or a File that acts like a Tempfile (close! method) def grab_file_from_uri(uri) Chef::Provider::RemoteFile::Fetcher.for_resource(uri, @new_resource, @current_resource).fetch end def current_resource_matches_target_checksum? @new_resource.checksum && @current_resource.checksum && @current_resource.checksum =~ /^#{Regexp.escape(@new_resource.checksum)}/ end end end end end chef-11.8.2/lib/chef/provider/deploy/0000755000004100000410000000000012254362222017341 5ustar www-datawww-datachef-11.8.2/lib/chef/provider/deploy/revision.rb0000644000004100000410000000546212254362222021533 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Author:: Tim Hinderliter () # Author:: Seth Falcon () # Copyright:: Copyright (c) 2009 Daniel DeLeo # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider' require 'chef/provider/deploy' require 'chef/json_compat' class Chef class Provider class Deploy class Revision < Chef::Provider::Deploy def all_releases sorted_releases end def action_deploy validate_release_history! super end def cleanup! super known_releases = sorted_releases Dir["#{new_resource.deploy_to}/releases/*"].each do |release_dir| unless known_releases.include?(release_dir) converge_by("Remove unknown release in #{release_dir}") do FileUtils.rm_rf(release_dir) end end end end protected def release_created(release) sorted_releases {|r| r.delete(release); r << release } end def release_deleted(release) sorted_releases { |r| r.delete(release)} end def release_slug scm_provider.revision_slug end private def sorted_releases cache = load_cache if block_given? yield cache save_cache(cache) end cache end def validate_release_history! sorted_releases do |release_list| release_list.each do |path| release_list.delete(path) unless ::File.exist?(path) end end end def sorted_releases_from_filesystem Dir.glob(new_resource.deploy_to + "/releases/*").sort_by { |d| ::File.ctime(d) } end def load_cache begin Chef::JSONCompat.from_json(Chef::FileCache.load("revision-deploys/#{new_resource.name}")) rescue Chef::Exceptions::FileNotFound sorted_releases_from_filesystem end end def save_cache(cache) Chef::FileCache.store("revision-deploys/#{new_resource.name}", cache.to_json) cache end end end end end chef-11.8.2/lib/chef/provider/deploy/timestamped.rb0000644000004100000410000000161612254362222022206 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 Daniel DeLeo # License:: Apache License, Version 2.0 # # 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. # class Chef class Provider class Deploy class Timestamped < Chef::Provider::Deploy protected def release_slug Time.now.utc.strftime("%Y%m%d%H%M%S") end end end end end chef-11.8.2/lib/chef/provider/env/0000755000004100000410000000000012254362222016635 5ustar www-datawww-datachef-11.8.2/lib/chef/provider/env/windows.rb0000644000004100000410000000442512254362222020661 0ustar www-datawww-data# # Author:: Doug MacEachern () # Copyright:: Copyright (c) 2010 VMware, Inc. # License:: Apache License, Version 2.0 # # 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. # if RUBY_PLATFORM =~ /mswin|mingw32|windows/ require 'ruby-wmi' require 'Win32API' end class Chef class Provider class Env class Windows < Chef::Provider::Env def create_env obj = env_obj(@new_resource.key_name) unless obj obj = WIN32OLE.connect("winmgmts://").get("Win32_Environment").spawninstance_ obj.name = @new_resource.key_name obj.username = "" end obj.variablevalue = @new_resource.value obj.put_ broadcast_env_change end def delete_env obj = env_obj(@new_resource.key_name) if obj obj.delete_ broadcast_env_change end end def env_value(key_name) obj = env_obj(key_name) return obj ? obj.variablevalue : nil end def env_obj(key_name) WMI::Win32_Environment.find(:first, :conditions => { :name => key_name }) end #see: http://msdn.microsoft.com/en-us/library/ms682653%28VS.85%29.aspx HWND_BROADCAST = 0xffff WM_SETTINGCHANGE = 0x001A SMTO_BLOCK = 0x0001 SMTO_ABORTIFHUNG = 0x0002 SMTO_NOTIMEOUTIFNOTHUNG = 0x0008 def broadcast_env_change result = 0 flags = SMTO_BLOCK | SMTO_ABORTIFHUNG | SMTO_NOTIMEOUTIFNOTHUNG @send_message ||= Win32API.new('user32', 'SendMessageTimeout', 'LLLPLLP', 'L') @send_message.call(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 'Environment', flags, 5000, result) end end end end end chef-11.8.2/lib/chef/provider/user/0000755000004100000410000000000012254362222017023 5ustar www-datawww-datachef-11.8.2/lib/chef/provider/user/pw.rb0000644000004100000410000000675612254362222020014 0ustar www-datawww-data# # Author:: Stephen Haynes () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/user' class Chef class Provider class User class Pw < Chef::Provider::User def load_current_resource super raise Chef::Exceptions::User, "Could not find binary /usr/sbin/pw for #{@new_resource}" unless ::File.exists?("/usr/sbin/pw") end def create_user command = "pw useradd" command << set_options run_command(:command => command) modify_password end def manage_user command = "pw usermod" command << set_options run_command(:command => command) modify_password end def remove_user command = "pw userdel #{@new_resource.username}" command << " -r" if @new_resource.supports[:manage_home] run_command(:command => command) end def check_lock case @current_resource.password when /^\*LOCKED\*/ @locked = true else @locked = false end @locked end def lock_user run_command(:command => "pw lock #{@new_resource.username}") end def unlock_user run_command(:command => "pw unlock #{@new_resource.username}") end def set_options opts = " #{@new_resource.username}" field_list = { 'comment' => "-c", 'home' => "-d", 'gid' => "-g", 'uid' => "-u", 'shell' => "-s" } field_list.sort{ |a,b| a[0] <=> b[0] }.each do |field, option| field_symbol = field.to_sym if @current_resource.send(field_symbol) != @new_resource.send(field_symbol) if @new_resource.send(field_symbol) Chef::Log.debug("#{@new_resource} setting #{field} to #{@new_resource.send(field_symbol)}") opts << " #{option} '#{@new_resource.send(field_symbol)}'" end end end if @new_resource.supports[:manage_home] Chef::Log.debug("#{@new_resource} is managing the users home directory") opts << " -m" end opts end def modify_password if @current_resource.password != @new_resource.password Chef::Log.debug("#{new_resource} updating password") command = "pw usermod #{@new_resource.username} -H 0" status = popen4(command, :waitlast => true) do |pid, stdin, stdout, stderr| stdin.puts "#{@new_resource.password}" end unless status.exitstatus == 0 raise Chef::Exceptions::User, "pw failed - #{status.inspect}!" end else Chef::Log.debug("#{new_resource} no change needed to password") end end end end end end chef-11.8.2/lib/chef/provider/user/solaris.rb0000644000004100000410000000516112254362222021027 0ustar www-datawww-data# # Author:: Stephen Nelson-Smith () # Author:: Jon Ramsey () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. class Chef class Provider class User class Solaris < Chef::Provider::User::Useradd UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:shell, "-s"], [:uid, "-u"]] attr_writer :password_file def initialize(new_resource, run_context) @password_file = "/etc/shadow" super end def create_user super manage_password end def manage_user manage_password super end private def manage_password if @current_resource.password != @new_resource.password && @new_resource.password Chef::Log.debug("#{@new_resource} setting password to #{@new_resource.password}") write_shadow_file end end def write_shadow_file buffer = Tempfile.new("shadow", "/etc") ::File.open(@password_file) do |shadow_file| shadow_file.each do |entry| user = entry.split(":").first if user == @new_resource.username buffer.write(updated_password(entry)) else buffer.write(entry) end end end buffer.close # FIXME: mostly duplicates code with file provider deploying a file mode = ::File.stat(@password_file).mode & 07777 uid = ::File.stat(@password_file).uid gid = ::File.stat(@password_file).gid FileUtils.chown uid, gid, buffer.path FileUtils.chmod mode, buffer.path FileUtils.mv buffer.path, @password_file end def updated_password(entry) fields = entry.split(":") fields[1] = @new_resource.password fields[2] = days_since_epoch fields.join(":") end def days_since_epoch (Time.now.to_i / 86400).floor end end end end end chef-11.8.2/lib/chef/provider/user/dscl.rb0000644000004100000410000002523312254362222020302 0ustar www-datawww-data# # Author:: Dreamcat4 () # Copyright:: Copyright (c) 2009 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/mixin/shell_out' require 'chef/provider/user' require 'openssl' class Chef class Provider class User class Dscl < Chef::Provider::User include Chef::Mixin::ShellOut NFS_HOME_DIRECTORY = %r{^NFSHomeDirectory: (.*)$} AUTHENTICATION_AUTHORITY = %r{^AuthenticationAuthority: (.*)$} def dscl(*args) shell_out("dscl . -#{args.join(' ')}") end def safe_dscl(*args) result = dscl(*args) return "" if ( args.first =~ /^delete/ ) && ( result.exitstatus != 0 ) raise(Chef::Exceptions::DsclCommandFailed,"dscl error: #{result.inspect}") unless result.exitstatus == 0 raise(Chef::Exceptions::DsclCommandFailed,"dscl error: #{result.inspect}") if result.stdout =~ /No such key: / return result.stdout end # This is handled in providers/group.rb by Etc.getgrnam() # def user_exists?(user) # users = safe_dscl("list /Users") # !! ( users =~ Regexp.new("\n#{user}\n") ) # end # get a free UID greater than 200 def get_free_uid(search_limit=1000) uid = nil; next_uid_guess = 200 users_uids = safe_dscl("list /Users uid") while(next_uid_guess < search_limit + 200) if users_uids =~ Regexp.new("#{Regexp.escape(next_uid_guess.to_s)}\n") next_uid_guess += 1 else uid = next_uid_guess break end end return uid || raise("uid not found. Exhausted. Searched #{search_limit} times") end def uid_used?(uid) return false unless uid users_uids = safe_dscl("list /Users uid") !! ( users_uids =~ Regexp.new("#{Regexp.escape(uid.to_s)}\n") ) end def set_uid @new_resource.uid(get_free_uid) if (@new_resource.uid.nil? || @new_resource.uid == '') if uid_used?(@new_resource.uid) raise(Chef::Exceptions::RequestedUIDUnavailable, "uid #{@new_resource.uid} is already in use") end safe_dscl("create /Users/#{@new_resource.username} UniqueID #{@new_resource.uid}") end def modify_home return safe_dscl("delete /Users/#{@new_resource.username} NFSHomeDirectory") if (@new_resource.home.nil? || @new_resource.home.empty?) if @new_resource.supports[:manage_home] validate_home_dir_specification! if (@current_resource.home == @new_resource.home) && !new_home_exists? ditto_home elsif !current_home_exists? && !new_home_exists? ditto_home elsif current_home_exists? move_home end end safe_dscl("create /Users/#{@new_resource.username} NFSHomeDirectory '#{@new_resource.home}'") end def osx_shadow_hash?(string) return !! ( string =~ /^[[:xdigit:]]{1240}$/ ) end def osx_salted_sha1?(string) return !! ( string =~ /^[[:xdigit:]]{48}$/ ) end def guid safe_dscl("read /Users/#{@new_resource.username} GeneratedUID").gsub(/GeneratedUID: /,"").strip end def shadow_hash_set? user_data = safe_dscl("read /Users/#{@new_resource.username}") if user_data =~ /AuthenticationAuthority: / && user_data =~ /ShadowHash/ true else false end end def modify_password if @new_resource.password shadow_hash = nil Chef::Log.debug("#{new_resource} updating password") if osx_shadow_hash?(@new_resource.password) shadow_hash = @new_resource.password.upcase else if osx_salted_sha1?(@new_resource.password) salted_sha1 = @new_resource.password.upcase else hex_salt = "" OpenSSL::Random.random_bytes(10).each_byte { |b| hex_salt << b.to_i.to_s(16) } hex_salt = hex_salt.slice(0...8) salt = [hex_salt].pack("H*") sha1 = ::OpenSSL::Digest::SHA1.hexdigest(salt+@new_resource.password) salted_sha1 = (hex_salt+sha1).upcase end shadow_hash = String.new("00000000"*155) shadow_hash[168] = salted_sha1 end ::File.open("/var/db/shadow/hash/#{guid}",'w',0600) do |output| output.puts shadow_hash end unless shadow_hash_set? safe_dscl("append /Users/#{@new_resource.username} AuthenticationAuthority ';ShadowHash;'") end end end def load_current_resource super raise Chef::Exceptions::User, "Could not find binary /usr/bin/dscl for #{@new_resource}" unless ::File.exists?("/usr/bin/dscl") end def create_user dscl_create_user dscl_create_comment set_uid dscl_set_gid modify_home dscl_set_shell modify_password end def manage_user dscl_create_user if diverged?(:username) dscl_create_comment if diverged?(:comment) set_uid if diverged?(:uid) dscl_set_gid if diverged?(:gid) modify_home if diverged?(:home) dscl_set_shell if diverged?(:shell) modify_password if diverged?(:password) end def dscl_create_user safe_dscl("create /Users/#{@new_resource.username}") end def dscl_create_comment safe_dscl("create /Users/#{@new_resource.username} RealName '#{@new_resource.comment}'") end def dscl_set_gid unless @new_resource.gid && @new_resource.gid.to_s.match(/^\d+$/) begin possible_gid = safe_dscl("read /Groups/#{@new_resource.gid} PrimaryGroupID").split(" ").last rescue Chef::Exceptions::DsclCommandFailed => e raise Chef::Exceptions::GroupIDNotFound.new("Group not found for #{@new_resource.gid} when creating user #{@new_resource.username}") end @new_resource.gid(possible_gid) if possible_gid && possible_gid.match(/^\d+$/) end safe_dscl("create /Users/#{@new_resource.username} PrimaryGroupID '#{@new_resource.gid}'") end def dscl_set_shell if @new_resource.password || ::File.exists?("#{@new_resource.shell}") safe_dscl("create /Users/#{@new_resource.username} UserShell '#{@new_resource.shell}'") else safe_dscl("create /Users/#{@new_resource.username} UserShell '/usr/bin/false'") end end def remove_user if @new_resource.supports[:manage_home] user_info = safe_dscl("read /Users/#{@new_resource.username}") if nfs_home_match = user_info.match(NFS_HOME_DIRECTORY) #nfs_home = safe_dscl("read /Users/#{@new_resource.username} NFSHomeDirectory") #nfs_home.gsub!(/NFSHomeDirectory: /,"").gsub!(/\n$/,"") nfs_home = nfs_home_match[1] FileUtils.rm_rf(nfs_home) end end # remove the user from its groups groups = [] Etc.group do |group| groups << group.name if group.mem.include?(@new_resource.username) end groups.each do |group_name| safe_dscl("delete /Groups/#{group_name} GroupMembership '#{@new_resource.username}'") end # remove user account safe_dscl("delete /Users/#{@new_resource.username}") end def locked? user_info = safe_dscl("read /Users/#{@new_resource.username}") if auth_authority_md = AUTHENTICATION_AUTHORITY.match(user_info) !!(auth_authority_md[1] =~ /DisabledUser/ ) else false end end def check_lock return @locked = locked? end def lock_user safe_dscl("append /Users/#{@new_resource.username} AuthenticationAuthority ';DisabledUser;'") end def unlock_user auth_info = safe_dscl("read /Users/#{@new_resource.username} AuthenticationAuthority") auth_string = auth_info.gsub(/AuthenticationAuthority: /,"").gsub(/;DisabledUser;/,"").strip#.gsub!(/[; ]*$/,"") safe_dscl("create /Users/#{@new_resource.username} AuthenticationAuthority '#{auth_string}'") end def validate_home_dir_specification! unless @new_resource.home =~ /^\// raise(Chef::Exceptions::InvalidHomeDirectory,"invalid path spec for User: '#{@new_resource.username}', home directory: '#{@new_resource.home}'") end end def current_home_exists? ::File.exist?("#{@current_resource.home}") end def new_home_exists? ::File.exist?("#{@new_resource.home}") end def ditto_home skel = "/System/Library/User Template/English.lproj" raise(Chef::Exceptions::User,"can't find skel at: #{skel}") unless ::File.exists?(skel) shell_out! "ditto '#{skel}' '#{@new_resource.home}'" ::FileUtils.chown_R(@new_resource.username,@new_resource.gid.to_s,@new_resource.home) end def move_home Chef::Log.debug("#{@new_resource} moving #{self} home from #{@current_resource.home} to #{@new_resource.home}") src = @current_resource.home FileUtils.mkdir_p(@new_resource.home) files = ::Dir.glob("#{src}/*", ::File::FNM_DOTMATCH) - ["#{src}/.","#{src}/.."] ::FileUtils.mv(files,@new_resource.home, :force => true) ::FileUtils.rmdir(src) ::FileUtils.chown_R(@new_resource.username,@new_resource.gid.to_s,@new_resource.home) end def diverged?(parameter) parameter_updated?(parameter) && (not @new_resource.send(parameter).nil?) end def parameter_updated?(parameter) not (@new_resource.send(parameter) == @current_resource.send(parameter)) end end end end end chef-11.8.2/lib/chef/provider/user/useradd.rb0000644000004100000410000001213312254362222020777 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'pathname' require 'chef/mixin/shell_out' require 'chef/provider/user' class Chef class Provider class User class Useradd < Chef::Provider::User include Chef::Mixin::ShellOut UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:password, "-p"], [:shell, "-s"], [:uid, "-u"]] def create_user command = compile_command("useradd") do |useradd| useradd.concat(universal_options) useradd.concat(useradd_options) end shell_out!(*command) end def manage_user if universal_options != "" command = compile_command("usermod") do |u| u.concat(universal_options) end shell_out!(*command) end end def remove_user command = [ "userdel" ] command << "-r" if managing_home_dir? command << new_resource.username shell_out!(*command) end def check_lock # we can get an exit code of 1 even when it's successful on # rhel/centos (redhat bug 578534). See additional error checks below. passwd_s = shell_out!("passwd", "-S", new_resource.username, :returns => [0,1]) status_line = passwd_s.stdout.split(' ') case status_line[1] when /^P/ @locked = false when /^N/ @locked = false when /^L/ @locked = true end unless passwd_s.exitstatus == 0 raise_lock_error = false if ['redhat', 'centos'].include?(node[:platform]) passwd_version_check = shell_out!('rpm -q passwd') passwd_version = passwd_version_check.stdout.chomp unless passwd_version == 'passwd-0.73-1' raise_lock_error = true end else raise_lock_error = true end raise Chef::Exceptions::User, "Cannot determine if #{new_resource} is locked!" if raise_lock_error end @locked end def lock_user shell_out!("usermod", "-L", new_resource.username) end def unlock_user shell_out!("usermod", "-U", new_resource.username) end def compile_command(base_command) base_command = Array(base_command) yield base_command base_command << new_resource.username base_command end def universal_options @universal_options ||= begin opts = [] # magic allows UNIVERSAL_OPTIONS to be overridden in a subclass self.class::UNIVERSAL_OPTIONS.each do |field, option| update_options(field, option, opts) end if updating_home? if managing_home_dir? Chef::Log.debug("#{new_resource} managing the users home directory") opts << "-d" << new_resource.home << "-m" else Chef::Log.debug("#{new_resource} setting home to #{new_resource.home}") opts << "-d" << new_resource.home end end opts << "-o" if new_resource.non_unique || new_resource.supports[:non_unique] opts end end def update_options(field, option, opts) if @current_resource.send(field).to_s != new_resource.send(field).to_s if new_resource.send(field) Chef::Log.debug("#{new_resource} setting #{field} to #{new_resource.send(field)}") opts << option << new_resource.send(field).to_s end end end def useradd_options opts = [] opts << "-r" if new_resource.system opts end def updating_home? # will return false if paths are equivalent # Pathname#cleanpath does a better job than ::File::expand_path (on both unix and windows) # ::File.expand_path("///tmp") == ::File.expand_path("/tmp") => false # ::File.expand_path("\\tmp") => "C:/tmp" return true if @current_resource.home.nil? && new_resource.home new_resource.home and Pathname.new(@current_resource.home).cleanpath != Pathname.new(new_resource.home).cleanpath end def managing_home_dir? new_resource.manage_home || new_resource.supports[:manage_home] end end end end end chef-11.8.2/lib/chef/provider/user/windows.rb0000644000004100000410000000727312254362222021053 0ustar www-datawww-data# # Author:: Doug MacEachern () # Copyright:: Copyright (c) 2010 VMware, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/user' if RUBY_PLATFORM =~ /mswin|mingw32|windows/ require 'chef/util/windows/net_user' end class Chef class Provider class User class Windows < Chef::Provider::User def initialize(new_resource,run_context) super @net_user = Chef::Util::Windows::NetUser.new(@new_resource.name) end def load_current_resource @current_resource = Chef::Resource::User.new(@new_resource.name) @current_resource.username(@new_resource.username) user_info = nil begin user_info = @net_user.get_info rescue @user_exists = false Chef::Log.debug("#{@new_resource} does not exist") end if user_info @current_resource.uid(user_info[:user_id]) @current_resource.gid(user_info[:primary_group_id]) @current_resource.comment(user_info[:full_name]) @current_resource.home(user_info[:home_dir]) @current_resource.shell(user_info[:script_path]) end @current_resource end # Check to see if the user needs any changes # # === Returns # :: If a change is required # :: If the users are identical def compare_user unless @net_user.validate_credentials(@new_resource.password) Chef::Log.debug("#{@new_resource} password has changed") return true end [ :uid, :gid, :comment, :home, :shell ].any? do |user_attrib| !@new_resource.send(user_attrib).nil? && @new_resource.send(user_attrib) != @current_resource.send(user_attrib) end end def create_user @net_user.add(set_options) end def manage_user @net_user.update(set_options) end def remove_user @net_user.delete end def check_lock @net_user.check_enabled end def lock_user @net_user.disable_account end def unlock_user @net_user.enable_account end def set_options opts = {:name => @new_resource.username} field_list = { 'comment' => 'full_name', 'home' => 'home_dir', 'gid' => 'primary_group_id', 'uid' => 'user_id', 'shell' => 'script_path', 'password' => 'password' } field_list.sort{ |a,b| a[0] <=> b[0] }.each do |field, option| field_symbol = field.to_sym if @current_resource.send(field_symbol) != @new_resource.send(field_symbol) if @new_resource.send(field_symbol) unless field_symbol == :password Chef::Log.debug("#{@new_resource} setting #{field} to #{@new_resource.send(field_symbol)}") end opts[option.to_sym] = @new_resource.send(field_symbol) end end end opts end end end end end chef-11.8.2/lib/chef/provider/user.rb0000644000004100000410000001456412254362222017362 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider' require 'chef/mixin/command' require 'etc' class Chef class Provider class User < Chef::Provider include Chef::Mixin::Command attr_accessor :user_exists, :locked def initialize(new_resource, run_context) super @user_exists = true @locked = nil @shadow_lib_ok = true @group_name_resolved = true end def convert_group_name if @new_resource.gid.is_a? String @new_resource.gid(Etc.getgrnam(@new_resource.gid).gid) end rescue ArgumentError => e @group_name_resolved = false end def whyrun_supported? true end def load_current_resource @current_resource = Chef::Resource::User.new(@new_resource.name) @current_resource.username(@new_resource.username) begin user_info = Etc.getpwnam(@new_resource.username) rescue ArgumentError => e @user_exists = false Chef::Log.debug("#{@new_resource} user does not exist") user_info = nil end if user_info @current_resource.uid(user_info.uid) @current_resource.gid(user_info.gid) @current_resource.comment(user_info.gecos) @current_resource.home(user_info.dir) @current_resource.shell(user_info.shell) @current_resource.password(user_info.passwd) if @new_resource.password && @current_resource.password == 'x' begin require 'shadow' rescue LoadError @shadow_lib_ok = false else shadow_info = Shadow::Passwd.getspnam(@new_resource.username) @current_resource.password(shadow_info.sp_pwdp) end end convert_group_name if @new_resource.gid end @current_resource end def define_resource_requirements requirements.assert(:all_actions) do |a| a.assertion { @group_name_resolved } a.failure_message Chef::Exceptions::User, "Couldn't lookup integer GID for group name #{@new_resource.gid}" a.whyrun "group name #{@new_resource.gid} does not exist. This will cause group assignment to fail. Assuming this group will have been created previously." end requirements.assert(:all_actions) do |a| a.assertion { @shadow_lib_ok } a.failure_message Chef::Exceptions::MissingLibrary, "You must have ruby-shadow installed for password support!" a.whyrun "ruby-shadow is not installed. Attempts to set user password will cause failure. Assuming that this gem will have been previously installed." + "Note that user update converge may report false-positive on the basis of mismatched password. " end requirements.assert(:modify, :lock, :unlock) do |a| a.assertion { @user_exists } a.failure_message(Chef::Exceptions::User, "Cannot modify user #{@new_resource} - does not exist!") a.whyrun("Assuming user #{@new_resource} would have been created") end end # Check to see if the user needs any changes # # === Returns # :: If a change is required # :: If the users are identical def compare_user changed = [ :comment, :home, :shell, :password ].select do |user_attrib| !@new_resource.send(user_attrib).nil? && @new_resource.send(user_attrib) != @current_resource.send(user_attrib) end changed += [ :uid, :gid ].select do |user_attrib| !@new_resource.send(user_attrib).nil? && @new_resource.send(user_attrib).to_s != @current_resource.send(user_attrib).to_s end changed.any? end def action_create if !@user_exists converge_by("create user #{@new_resource}") do create_user Chef::Log.info("#{@new_resource} created") end elsif compare_user converge_by("alter user #{@new_resource}") do manage_user Chef::Log.info("#{@new_resource} altered") end end end def action_remove if @user_exists converge_by("remove user #{@new_resource}") do remove_user Chef::Log.info("#{@new_resource} removed") end end end def remove_user raise NotImplementedError end def action_manage if @user_exists && compare_user converge_by("manage user #{@new_resource}") do manage_user Chef::Log.info("#{@new_resource} managed") end end end def manage_user raise NotImplementedError end def action_modify if compare_user converge_by("modify user #{@new_resource}") do manage_user Chef::Log.info("#{@new_resource} modified") end end end def action_lock if check_lock() == false converge_by("lock the user #{@new_resource}") do lock_user Chef::Log.info("#{@new_resource} locked") end else Chef::Log.debug("#{@new_resource} already locked - nothing to do") end end def check_lock raise NotImplementedError end def lock_user raise NotImplementedError end def action_unlock if check_lock() == true converge_by("unlock user #{@new_resource}") do unlock_user Chef::Log.info("#{@new_resource} unlocked") end else Chef::Log.debug("#{@new_resource} already unlocked - nothing to do") end end def unlock_user raise NotImplementedError end end end end chef-11.8.2/lib/chef/provider/file.rb0000644000004100000410000003753612254362222017327 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2008-2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/config' require 'chef/log' require 'chef/resource/file' require 'chef/provider' require 'etc' require 'fileutils' require 'chef/scan_access_control' require 'chef/mixin/checksum' require 'chef/mixin/shell_out' require 'chef/mixin/file_class' require 'chef/util/backup' require 'chef/util/diff' require 'chef/deprecation/provider/file' require 'chef/deprecation/warnings' require 'chef/file_content_management/deploy' # The Tao of File Providers: # - the content provider must always return a tempfile that we can delete/mv # - do_create_file shall always create the file first and obey umask when perms are not specified # - do_contents_changes may assume the destination file exists (simplifies exception checking, # and always gives us something to diff against) # - do_contents_changes must restore the perms to the dest file and not obliterate them with # random tempfile permissions # - do_acl_changes may assume perms were not modified between lcr and when it runs (although the # file may have been created) class Chef class Provider class File < Chef::Provider include Chef::Mixin::EnforceOwnershipAndPermissions include Chef::Mixin::Checksum include Chef::Mixin::ShellOut include Chef::Util::Selinux include Chef::Mixin::FileClass extend Chef::Deprecation::Warnings include Chef::Deprecation::Provider::File add_deprecation_warnings_for(Chef::Deprecation::Provider::File.instance_methods) attr_reader :deployment_strategy def initialize(new_resource, run_context) @content_class ||= Chef::Provider::File::Content if new_resource.respond_to?(:atomic_update) @deployment_strategy = Chef::FileContentManagement::Deploy.strategy(new_resource.atomic_update) end super end def whyrun_supported? true end def load_current_resource # Let children resources override constructing the @current_resource @current_resource ||= Chef::Resource::File.new(@new_resource.name) @current_resource.path(@new_resource.path) if ::File.exists?(@current_resource.path) && ::File.file?(::File.realpath(@current_resource.path)) if @action != :create_if_missing && @current_resource.respond_to?(:checksum) @current_resource.checksum(checksum(@current_resource.path)) end load_resource_attributes_from_file(@current_resource) end @current_resource end def define_resource_requirements # deep inside FAC we have to assert requirements, so call FACs hook to set that up access_controls.define_resource_requirements # Make sure the parent directory exists, otherwise fail. For why-run assume it would have been created. requirements.assert(:create, :create_if_missing, :touch) do |a| parent_directory = ::File.dirname(@new_resource.path) a.assertion { ::File.directory?(parent_directory) } a.failure_message(Chef::Exceptions::EnclosingDirectoryDoesNotExist, "Parent directory #{parent_directory} does not exist.") a.whyrun("Assuming directory #{parent_directory} would have been created") end # Make sure the file is deletable if it exists, otherwise fail. if ::File.exists?(@new_resource.path) requirements.assert(:delete) do |a| a.assertion { ::File.writable?(@new_resource.path) } a.failure_message(Chef::Exceptions::InsufficientPermissions,"File #{@new_resource.path} exists but is not writable so it cannot be deleted") end end error, reason, whyrun_message = inspect_existing_fs_entry requirements.assert(:create) do |a| a.assertion { error.nil? } a.failure_message(error, reason) a.whyrun(whyrun_message) # Subsequent attempts to read the fs entry at the path (e.g., for # calculating checksums) could blow up, so give up trying to continue # why-running. a.block_action! end end def action_create do_unlink do_create_file do_contents_changes do_acl_changes do_selinux load_resource_attributes_from_file(@new_resource) end def action_create_if_missing if ::File.exists?(@new_resource.path) Chef::Log.debug("#{@new_resource} exists at #{@new_resource.path} taking no action.") else action_create end end def action_delete if ::File.exists?(@new_resource.path) converge_by("delete file #{@new_resource.path}") do do_backup unless file_class.symlink?(@new_resource.path) ::File.delete(@new_resource.path) Chef::Log.info("#{@new_resource} deleted file at #{@new_resource.path}") end end end def action_touch action_create converge_by("update utime on file #{@new_resource.path}") do time = Time.now ::File.utime(time, time, @new_resource.path) Chef::Log.info("#{@new_resource} updated atime and mtime to #{time}") end end # Implementation components *should* follow symlinks when managing access # control (e.g., use chmod instead of lchmod even if the path we're # managing is a symlink). def manage_symlink_access? false end private # Handles resource requirements for action :create when some fs entry # already exists at the destination path. For actions other than create, # we don't care what kind of thing is at the destination path because: # * for :create_if_missing, we're assuming the user wanted to avoid blowing away the non-file here # * for :touch, we can modify perms of whatever is at this path, regardless of its type # * for :delete, we can blow away whatever is here, regardless of its type # # For the action :create case, we need to deal with user-selectable # behavior to see if we're in an error condition. # * If there's no file at the destination path currently, we're cool to # create it. # * If the fs entry that currently exists at the destination is a regular # file, we're cool to update it with new content. # * If the fs entry is a symlink AND the resource has # `manage_symlink_source` enabled, we need to verify that the symlink is # a valid pointer to a real file. If it is, we can manage content and # permissions on the symlink source, otherwise, error. # * If `manage_symlink_source` is not enabled, fall through. # * If force_unlink is true, action :create will unlink whatever is in the way. # * If force_unlink is false, we're in an exceptional situation, so we # want to error. # # Note that this method returns values to be used with requirement # assertions, which then decide whether or not to raise or issue a # warning for whyrun mode. def inspect_existing_fs_entry path = @new_resource.path if !l_exist?(path) [nil, nil, nil] elsif real_file?(path) [nil, nil, nil] elsif file_class.symlink?(path) && @new_resource.manage_symlink_source verify_symlink_sanity(path) elsif file_class.symlink?(@new_resource.path) && @new_resource.manage_symlink_source.nil? Chef::Log.warn("File #{path} managed by #{@new_resource} is really a symlink. Managing the source file instead.") Chef::Log.warn("Disable this warning by setting `manage_symlink_source true` on the resource") Chef::Log.warn("In a future Chef release, 'manage_symlink_source' will not be enabled by default") verify_symlink_sanity(path) elsif @new_resource.force_unlink [nil, nil, nil] else [ Chef::Exceptions::FileTypeMismatch, "File #{path} exists, but is a #{file_type_string(@new_resource.path)}, set force_unlink to true to remove", "Assuming #{file_type_string(@new_resource.path)} at #{@new_resource.path} would have been removed by a previous resource" ] end end # Returns values suitable for use in a requirements assertion statement # when managing symlink source. If we're managing symlink source we can # hit 3 error cases: # 1. Symlink to nowhere: File.realpath(symlink) -> raise Errno::ENOENT # 2. Symlink loop: File.realpath(symlink) -> raise Errno::ELOOP # 3. Symlink to not-a-real-file: File.realpath(symlink) -> (directory|blockdev|etc.) # If any of the above apply, returns a 3-tuple of Exception class, # exception message, whyrun message; otherwise returns a 3-tuple of nil. def verify_symlink_sanity(path) real_path = ::File.realpath(path) if real_file?(real_path) [nil, nil, nil] else [ Chef::Exceptions::FileTypeMismatch, "File #{path} exists, but is a symlink to #{real_path} which is a #{file_type_string(real_path)}. " + "Disable manage_symlink_source and set force_unlink to remove it.", "Assuming symlink #{path} or source file #{real_path} would have been fixed by a previous resource" ] end rescue Errno::ELOOP [ Chef::Exceptions::InvalidSymlink, "Symlink at #{path} (pointing to #{::File.readlink(path)}) exists but attempting to resolve it creates a loop", "Assuming symlink loop would be fixed by a previous resource" ] rescue Errno::ENOENT [ Chef::Exceptions::InvalidSymlink, "Symlink at #{path} (pointing to #{::File.readlink(path)}) exists but attempting to resolve it leads to a nonexistent file", "Assuming symlink source would be created by a previous resource" ] end def content @content ||= begin load_current_resource if @current_resource.nil? @content_class.new(@new_resource, @current_resource, @run_context) end end def file_type_string(path) case when ::File.blockdev?(path) "block device" when ::File.chardev?(path) "char device" when ::File.directory?(path) "directory" when ::File.pipe?(path) "pipe" when ::File.socket?(path) "socket" when file_class.symlink?(path) "symlink" else "unknown filetype" end end def real_file?(path) !file_class.symlink?(path) && ::File.file?(path) end # Similar to File.exist?, but also returns true in the case that the # named file is a broken symlink. def l_exist?(path) ::File.exist?(path) || file_class.symlink?(path) end def unlink(path) # Directories can not be unlinked. Remove them using FileUtils. if ::File.directory?(path) FileUtils.rm_rf(path) else ::File.unlink(path) end end def do_unlink @file_unlinked = false if @new_resource.force_unlink if !real_file?(@new_resource.path) # unlink things that aren't normal files description = "unlink #{file_type_string(@new_resource.path)} at #{@new_resource.path}" converge_by(description) do unlink(@new_resource.path) end @current_resource.checksum = nil @file_unlinked = true end end end def file_unlinked? @file_unlinked == true end def do_create_file @file_created = false if !::File.exists?(@new_resource.path) || file_unlinked? converge_by("create new file #{@new_resource.path}") do deployment_strategy.create(@new_resource.path) Chef::Log.info("#{@new_resource} created file #{@new_resource.path}") end @file_created = true end end # do_contents_changes needs to know if do_create_file created a file or not def file_created? @file_created == true end def do_backup(file = nil) Chef::Util::Backup.new(@new_resource, file).backup! end def diff @diff ||= Chef::Util::Diff.new end def update_file_contents do_backup unless file_created? deployment_strategy.deploy(tempfile.path, ::File.realpath(@new_resource.path)) Chef::Log.info("#{@new_resource} updated file contents #{@new_resource.path}") @new_resource.checksum(checksum(@new_resource.path)) # for reporting end def do_contents_changes # a nil tempfile is okay, means the resource has no content or no new content return if tempfile.nil? # but a tempfile that has no path or doesn't exist should not happen if tempfile.path.nil? || !::File.exists?(tempfile.path) raise "chef-client is confused, trying to deploy a file that has no path or does not exist..." end # the file? on the next line suppresses the case in why-run when we have a not-file here that would have otherwise been removed if ::File.file?(@new_resource.path) && contents_changed? diff.diff(@current_resource.path, tempfile.path) @new_resource.diff( diff.for_reporting ) unless file_created? description = [ "update content in file #{@new_resource.path} from #{short_cksum(@current_resource.checksum)} to #{short_cksum(checksum(tempfile.path))}" ] description << diff.for_output converge_by(description) do update_file_contents end end # unlink necessary to clean up in why-run mode tempfile.unlink end # This logic ideally will be made into some kind of generic # platform-dependent post-converge hook for file-like # resources, but for now we only have the single selinux use # case. def do_selinux(recursive = false) if resource_updated? && Chef::Config[:enable_selinux_file_permission_fixup] if selinux_enabled? converge_by("restore selinux security context") do restore_security_context(::File.realpath(@new_resource.path), recursive) end else Chef::Log.debug "selinux utilities can not be found. Skipping selinux permission fixup." end end end def do_acl_changes if access_controls.requires_changes? converge_by(access_controls.describe_changes) do access_controls.set_all end end end def contents_changed? checksum(tempfile.path) != @current_resource.checksum end def tempfile content.tempfile end def short_cksum(checksum) return "none" if checksum.nil? checksum.slice(0,6) end def load_resource_attributes_from_file(resource) if Chef::Platform.windows? # This is a work around for CHEF-3554. # OC-6534: is tracking the real fix for this workaround. # Add support for Windows equivalent, or implicit resource # reporting won't work for Windows. return end acl_scanner = ScanAccessControl.new(@new_resource, resource) acl_scanner.set_all! end end end end chef-11.8.2/lib/chef/provider/mdadm.rb0000644000004100000410000000713512254362222017462 0ustar www-datawww-data# # Author:: Joe Williams () # Copyright:: Copyright (c) 2009 Joe Williams # License:: Apache License, Version 2.0 # # 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. # require 'chef/log' require 'chef/mixin/shell_out' require 'chef/provider' class Chef class Provider class Mdadm < Chef::Provider include Chef::Mixin::ShellOut def popen4 raise Exception, "deprecated" end def whyrun_supported? true end def load_current_resource @current_resource = Chef::Resource::Mdadm.new(@new_resource.name) @current_resource.raid_device(@new_resource.raid_device) Chef::Log.debug("#{@new_resource} checking for software raid device #{@current_resource.raid_device}") device_not_found = 4 mdadm = shell_out!("mdadm --detail --test #{@new_resource.raid_device}", :returns => [0,device_not_found]) exists = (mdadm.status == 0) @current_resource.exists(exists) end def action_create unless @current_resource.exists converge_by("create RAID device #{new_resource.raid_device}") do command = "yes | mdadm --create #{@new_resource.raid_device} --level #{@new_resource.level}" command << " --chunk=#{@new_resource.chunk}" unless @new_resource.level == 1 command << " --metadata=#{@new_resource.metadata}" command << " --bitmap=#{@new_resource.bitmap}" if @new_resource.bitmap command << " --raid-devices #{@new_resource.devices.length} #{@new_resource.devices.join(" ")}" Chef::Log.debug("#{@new_resource} mdadm command: #{command}") shell_out!(command) Chef::Log.info("#{@new_resource} created raid device (#{@new_resource.raid_device})") end else Chef::Log.debug("#{@new_resource} raid device already exists, skipping create (#{@new_resource.raid_device})") end end def action_assemble unless @current_resource.exists converge_by("assemble RAID device #{new_resource.raid_device}") do command = "yes | mdadm --assemble #{@new_resource.raid_device} #{@new_resource.devices.join(" ")}" Chef::Log.debug("#{@new_resource} mdadm command: #{command}") shell_out!(command) Chef::Log.info("#{@new_resource} assembled raid device (#{@new_resource.raid_device})") end else Chef::Log.debug("#{@new_resource} raid device already exists, skipping assemble (#{@new_resource.raid_device})") end end def action_stop if @current_resource.exists converge_by("stop RAID device #{new_resource.raid_device}") do command = "yes | mdadm --stop #{@new_resource.raid_device}" Chef::Log.debug("#{@new_resource} mdadm command: #{command}") shell_out!(command) Chef::Log.info("#{@new_resource} stopped raid device (#{@new_resource.raid_device})") end else Chef::Log.debug("#{@new_resource} raid device doesn't exist (#{@new_resource.raid_device}) - not stopping") end end end end end chef-11.8.2/lib/chef/provider/powershell_script.rb0000644000004100000410000000560112254362222022144 0ustar www-datawww-data# # Author:: Adam Edwards () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/windows_script' class Chef class Provider class PowershellScript < Chef::Provider::WindowsScript protected EXIT_STATUS_NORMALIZATION_SCRIPT = "\nif ($? -eq $true) {exit 0} elseif ( $LASTEXITCODE -ne 0) {exit $LASTEXITCODE} else { exit 1 }" EXIT_STATUS_RESET_SCRIPT = "$LASTEXITCODE=0\n" # Process exit codes are strange with PowerShell. Unless you # explicitly call exit in Powershell, the powershell.exe # interpreter returns only 0 for success or 1 for failure. Since # we'd like to get specific exit codes from executable tools run # with Powershell, we do some work using the automatic variables # $? and $LASTEXITCODE to return the process exit code of the # last process run in the script if it is the last command # executed, otherwise 0 or 1 based on whether $? is set to true # (success, where we return 0) or false (where we return 1). def NormalizeScriptExitStatus( code ) @code = (! code.nil?) ? ( EXIT_STATUS_RESET_SCRIPT + code + EXIT_STATUS_NORMALIZATION_SCRIPT ) : nil end public def initialize (new_resource, run_context) super(new_resource, run_context, '.ps1') NormalizeScriptExitStatus(new_resource.code) end def flags default_flags = [ "-NoLogo", "-NonInteractive", "-NoProfile", "-ExecutionPolicy RemoteSigned", # Powershell will hang if STDIN is redirected # http://connect.microsoft.com/PowerShell/feedback/details/572313/powershell-exe-can-hang-if-stdin-is-redirected "-InputFormat None", # Must use -File rather than -Command to launch the script # file created by the base class that contains the script # code -- otherwise, powershell.exe does not propagate the # error status of a failed Windows process that ran at the # end of the script, it gets changed to '1'. "-File" ] interpreter_flags = default_flags.join(' ') if ! (@new_resource.flags.nil?) interpreter_flags = [@new_resource.flags, interpreter_flags].join(' ') end interpreter_flags end end end end chef-11.8.2/lib/chef/provider/script.rb0000644000004100000410000000353012254362222017677 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'tempfile' require 'chef/provider/execute' class Chef class Provider class Script < Chef::Provider::Execute def initialize(new_resource, run_context) super @code = @new_resource.code end def action_run script_file.puts(@code) script_file.close set_owner_and_group @new_resource.command("\"#{interpreter}\" #{flags} \"#{script_file.path}\"") super converge_by(nil) do # ensure script is unlinked at end of converge! unlink_script_file end end def set_owner_and_group # FileUtils itself implements a no-op if +user+ or +group+ are nil # You can prove this by running FileUtils.chown(nil,nil,'/tmp/file') # as an unprivileged user. FileUtils.chown(@new_resource.user, @new_resource.group, script_file.path) end def script_file @script_file ||= Tempfile.open("chef-script") end def unlink_script_file @script_file && @script_file.close! end def interpreter @new_resource.interpreter end def flags @new_resource.flags end end end end chef-11.8.2/lib/chef/provider/cron.rb0000644000004100000410000001660212254362222017340 0ustar www-datawww-data# # Author:: Bryan McLellan (btm@loftninjas.org) # Copyright:: Copyright (c) 2009 Bryan McLellan # License:: Apache License, Version 2.0 # # 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. # require 'chef/log' require 'chef/mixin/command' require 'chef/provider' class Chef class Provider class Cron < Chef::Provider include Chef::Mixin::Command CRON_PATTERN = /\A([-0-9*,\/]+)\s([-0-9*,\/]+)\s([-0-9*,\/]+)\s([-0-9*,\/]+|[a-zA-Z]{3})\s([-0-9*,\/]+|[a-zA-Z]{3})\s(.*)/ ENV_PATTERN = /\A(\S+)=(\S*)/ CRON_ATTRIBUTES = [:minute, :hour, :day, :month, :weekday, :command, :mailto, :path, :shell, :home, :environment] def initialize(new_resource, run_context) super(new_resource, run_context) @cron_exists = false @cron_empty = false end attr_accessor :cron_exists, :cron_empty def whyrun_supported? true end def load_current_resource crontab_lines = [] @current_resource = Chef::Resource::Cron.new(@new_resource.name) @current_resource.user(@new_resource.user) @cron_exists = false if crontab = read_crontab cron_found = false crontab.each_line do |line| case line.chomp when "# Chef Name: #{@new_resource.name}" Chef::Log.debug("Found cron '#{@new_resource.name}'") cron_found = true @cron_exists = true next when ENV_PATTERN set_environment_var($1, $2) if cron_found next when CRON_PATTERN if cron_found @current_resource.minute($1) @current_resource.hour($2) @current_resource.day($3) @current_resource.month($4) @current_resource.weekday($5) @current_resource.command($6) cron_found=false end next else cron_found=false # We've got a Chef comment with no following crontab line next end end Chef::Log.debug("Cron '#{@new_resource.name}' not found") unless @cron_exists else Chef::Log.debug("Cron empty for '#{@new_resource.user}'") @cron_empty = true end @current_resource end def cron_different? CRON_ATTRIBUTES.any? do |cron_var| !@new_resource.send(cron_var).nil? && @new_resource.send(cron_var) != @current_resource.send(cron_var) end end def action_create crontab = String.new newcron = String.new cron_found = false newcron = get_crontab_entry if @cron_exists unless cron_different? Chef::Log.debug("Skipping existing cron entry '#{@new_resource.name}'") return end read_crontab.each_line do |line| case line.chomp when "# Chef Name: #{@new_resource.name}" cron_found = true next when ENV_PATTERN crontab << line unless cron_found next when CRON_PATTERN if cron_found cron_found = false crontab << newcron next end else if cron_found # We've got a Chef comment with no following crontab line crontab << newcron cron_found = false end end crontab << line end # Handle edge case where the Chef comment is the last line in the current crontab crontab << newcron if cron_found converge_by("update crontab entry for #{@new_resource}") do write_crontab crontab Chef::Log.info("#{@new_resource} updated crontab entry") end else crontab = read_crontab unless @cron_empty crontab << newcron converge_by("add crontab entry for #{@new_resource}") do write_crontab crontab Chef::Log.info("#{@new_resource} added crontab entry") end end end def action_delete if @cron_exists crontab = String.new cron_found = false read_crontab.each_line do |line| case line.chomp when "# Chef Name: #{@new_resource.name}" cron_found = true next when ENV_PATTERN next if cron_found when CRON_PATTERN if cron_found cron_found = false next end else # We've got a Chef comment with no following crontab line cron_found = false end crontab << line end description = cron_found ? "remove #{@new_resource.name} from crontab" : "save unmodified crontab" converge_by(description) do write_crontab crontab Chef::Log.info("#{@new_resource} deleted crontab entry") end end end private def set_environment_var(attr_name, attr_value) if %w(MAILTO PATH SHELL HOME).include?(attr_name) @current_resource.send(attr_name.downcase.to_sym, attr_value) else @current_resource.environment(@current_resource.environment.merge(attr_name => attr_value)) end end def read_crontab crontab = nil status = popen4("crontab -l -u #{@new_resource.user}") do |pid, stdin, stdout, stderr| crontab = stdout.read end if status.exitstatus > 1 raise Chef::Exceptions::Cron, "Error determining state of #{@new_resource.name}, exit: #{status.exitstatus}" end crontab end def write_crontab(crontab) write_exception = false status = popen4("crontab -u #{@new_resource.user} -", :waitlast => true) do |pid, stdin, stdout, stderr| begin stdin.write crontab rescue Errno::EPIPE => e # popen4 could yield while child has already died. write_exception = true Chef::Log.debug("#{e.message}") end end if status.exitstatus > 0 || write_exception raise Chef::Exceptions::Cron, "Error updating state of #{@new_resource.name}, exit: #{status.exitstatus}" end end def get_crontab_entry newcron = "" newcron << "# Chef Name: #{new_resource.name}\n" [ :mailto, :path, :shell, :home ].each do |v| newcron << "#{v.to_s.upcase}=#{@new_resource.send(v)}\n" if @new_resource.send(v) end @new_resource.environment.each do |name, value| newcron << "#{name}=#{value}\n" end newcron << "#{@new_resource.minute} #{@new_resource.hour} #{@new_resource.day} #{@new_resource.month} #{@new_resource.weekday} #{@new_resource.command}\n" newcron end end end end chef-11.8.2/lib/chef/provider/log.rb0000644000004100000410000000247312254362222017161 0ustar www-datawww-data# # Author:: Cary Penniman () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Provider class Log # Chef log provider, allows logging to chef's logs from recipes class ChefLog < Chef::Provider # No concept of a 'current' resource for logs, this is a no-op # # === Return # true:: Always return true def load_current_resource true end # Write the log to Chef's log # # === Return # true:: Always return true def action_write Chef::Log.send(@new_resource.level, @new_resource.message) @new_resource.updated_by_last_action(true) end end end end end chef-11.8.2/lib/chef/provider/mount/0000755000004100000410000000000012254362222017207 5ustar www-datawww-datachef-11.8.2/lib/chef/provider/mount/mount.rb0000644000004100000410000002336312254362222020705 0ustar www-datawww-data# # Author:: Joshua Timberman () # Copyright:: Copyright (c) 2009 Opscode, Inc # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/mount' require 'chef/log' require 'chef/mixin/shell_out' class Chef class Provider class Mount class Mount < Chef::Provider::Mount include Chef::Mixin::ShellOut def initialize(new_resource, run_context) super @real_device = nil end attr_accessor :real_device def load_current_resource @current_resource = Chef::Resource::Mount.new(@new_resource.name) @current_resource.mount_point(@new_resource.mount_point) @current_resource.device(@new_resource.device) mounted? enabled? end def mountable? # only check for existence of non-remote devices if (device_should_exist? && !::File.exists?(device_real) ) raise Chef::Exceptions::Mount, "Device #{@new_resource.device} does not exist" elsif( @new_resource.mount_point != "none" && !::File.exists?(@new_resource.mount_point) ) raise Chef::Exceptions::Mount, "Mount point #{@new_resource.mount_point} does not exist" end return true end def enabled? # Check to see if there is a entry in /etc/fstab. Last entry for a volume wins. enabled = false ::File.foreach("/etc/fstab") do |line| case line when /^[#\s]/ next when /^#{device_fstab_regex}\s+#{Regexp.escape(@new_resource.mount_point)}\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/ enabled = true @current_resource.fstype($1) @current_resource.options($2) @current_resource.dump($3.to_i) @current_resource.pass($4.to_i) Chef::Log.debug("Found mount #{device_fstab} to #{@new_resource.mount_point} in /etc/fstab") next when /^[\/\w]+\s+#{Regexp.escape(@new_resource.mount_point)}\s+/ enabled = false Chef::Log.debug("Found conflicting mount point #{@new_resource.mount_point} in /etc/fstab") end end @current_resource.enabled(enabled) end def mounted? mounted = false # "mount" outputs the mount points as real paths. Convert # the mount_point of the resource to a real path in case it # contains symlinks in its parents dirs. real_mount_point = if ::File.exists? @new_resource.mount_point ::File.realpath(@new_resource.mount_point) else @new_resource.mount_point end shell_out!("mount").stdout.each_line do |line| case line when /^#{device_mount_regex}\s+on\s+#{Regexp.escape(real_mount_point)}/ mounted = true Chef::Log.debug("Special device #{device_logstring} mounted as #{real_mount_point}") when /^([\/\w])+\son\s#{Regexp.escape(real_mount_point)}\s+/ mounted = false Chef::Log.debug("Special device #{$~[1]} mounted as #{real_mount_point}") end end @current_resource.mounted(mounted) end def mount_fs unless @current_resource.mounted mountable? command = "mount -t #{@new_resource.fstype}" command << " -o #{@new_resource.options.join(',')}" unless @new_resource.options.nil? || @new_resource.options.empty? command << case @new_resource.device_type when :device " #{device_real}" when :label " -L #{@new_resource.device}" when :uuid " -U #{@new_resource.device}" end command << " #{@new_resource.mount_point}" shell_out!(command) Chef::Log.debug("#{@new_resource} is mounted at #{@new_resource.mount_point}") else Chef::Log.debug("#{@new_resource} is already mounted at #{@new_resource.mount_point}") end end def umount_fs if @current_resource.mounted shell_out!("umount #{@new_resource.mount_point}") Chef::Log.debug("#{@new_resource} is no longer mounted at #{@new_resource.mount_point}") else Chef::Log.debug("#{@new_resource} is not mounted at #{@new_resource.mount_point}") end end def remount_command return "mount -o remount #{@new_resource.mount_point}" end def remount_fs if @current_resource.mounted and @new_resource.supports[:remount] shell_out!(remount_command) @new_resource.updated_by_last_action(true) Chef::Log.debug("#{@new_resource} is remounted at #{@new_resource.mount_point}") elsif @current_resource.mounted umount_fs sleep 1 mount_fs else Chef::Log.debug("#{@new_resource} is not mounted at #{@new_resource.mount_point} - nothing to do") end end def enable_fs if @current_resource.enabled && mount_options_unchanged? Chef::Log.debug("#{@new_resource} is already enabled - nothing to do") return nil end if @current_resource.enabled # The current options don't match what we have, so # disable, then enable. disable_fs end ::File.open("/etc/fstab", "a") do |fstab| fstab.puts("#{device_fstab} #{@new_resource.mount_point} #{@new_resource.fstype} #{@new_resource.options.nil? ? "defaults" : @new_resource.options.join(",")} #{@new_resource.dump} #{@new_resource.pass}") Chef::Log.debug("#{@new_resource} is enabled at #{@new_resource.mount_point}") end end def disable_fs if @current_resource.enabled contents = [] found = false ::File.readlines("/etc/fstab").reverse_each do |line| if !found && line =~ /^#{device_fstab_regex}\s+#{Regexp.escape(@new_resource.mount_point)}/ found = true Chef::Log.debug("#{@new_resource} is removed from fstab") next else contents << line end end ::File.open("/etc/fstab", "w") do |fstab| contents.reverse_each { |line| fstab.puts line} end else Chef::Log.debug("#{@new_resource} is not enabled - nothing to do") end end def network_device? @new_resource.device =~ /:/ || @new_resource.device =~ /\/\// end def device_should_exist? ( @new_resource.device != "none" ) && ( not network_device? ) && ( not %w[ tmpfs fuse ].include? @new_resource.fstype ) end private def device_fstab case @new_resource.device_type when :device @new_resource.device when :label "LABEL=#{@new_resource.device}" when :uuid "UUID=#{@new_resource.device}" end end def device_real if @real_device == nil if @new_resource.device_type == :device @real_device = @new_resource.device else @real_device = "" status = popen4("/sbin/findfs #{device_fstab}") do |pid, stdin, stdout, stderr| device_line = stdout.first # stdout.first consumes @real_device = device_line.chomp unless device_line.nil? end end end @real_device end def device_logstring case @new_resource.device_type when :device "#{device_real}" when :label "#{device_real} with label #{@new_resource.device}" when :uuid "#{device_real} with uuid #{@new_resource.device}" end end def device_mount_regex if network_device? # ignore trailing slash Regexp.escape(device_real)+"/?" elsif ::File.symlink?(device_real) # This regular expression tries to match device_real. If that does not match it will try to match the target of device_real. # So given a symlink like this: # /dev/mapper/vgroot-tmp.vol -> /dev/dm-9 # First it will try to match "/dev/mapper/vgroot-tmp.vol". If there is no match it will try matching for "/dev/dm-9". "(?:#{Regexp.escape(device_real)}|#{Regexp.escape(::File.readlink(device_real))})" else Regexp.escape(device_real) end end def device_fstab_regex if @new_resource.device_type == :device device_mount_regex else device_fstab end end def mount_options_unchanged? @current_resource.fstype == @new_resource.fstype and @current_resource.options == @new_resource.options and @current_resource.dump == @new_resource.dump and @current_resource.pass == @new_resource.pass end end end end end chef-11.8.2/lib/chef/provider/mount/aix.rb0000644000004100000410000001557512254362222020332 0ustar www-datawww-data# # Author:: # Copyright:: Copyright (c) 2009 Opscode, Inc # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/mount' class Chef class Provider class Mount class Aix < Chef::Provider::Mount::Mount # Override for aix specific handling def initialize(new_resource, run_context) super # options and fstype are set to "defaults" and "auto" respectively in the Mount Resource class. These options are not valid for AIX, override them. if @new_resource.options[0] == "defaults" @new_resource.options.clear end if @new_resource.fstype == "auto" @new_resource.fstype = nil end end def enabled? # Check to see if there is an entry in /etc/filesystems. Last entry for a volume wins. Using command "lsfs" to fetch entries. enabled = false # lsfs o/p = #MountPoint:Device:Vfs:Nodename:Type:Size:Options:AutoMount:Acct # search only for current mount point shell_out("lsfs -c #{@new_resource.mount_point}").stdout.each_line do | line | case line when /^#\s/ next when /^#{Regexp.escape(@new_resource.mount_point)}:#{device_fstab_regex}:(\S+):(\[\S+\])?:(\S+)?:(\S+):(\S+):(\S+):(\S+)/ # mount point entry with ipv6 address for nodename (ipv6 address use ':') enabled = true @current_resource.fstype($1) @current_resource.options($5) Chef::Log.debug("Found mount #{device_fstab} to #{@new_resource.mount_point} in /etc/filesystems") next when /^#{Regexp.escape(@new_resource.mount_point)}:#{device_fstab_regex}::(\S+):(\S+)?:(\S+)?:(\S+):(\S+):(\S+):(\S+)/ # mount point entry with hostname or ipv4 address enabled = true @current_resource.fstype($1) @current_resource.options($5) Chef::Log.debug("Found mount #{device_fstab} to #{@new_resource.mount_point} in /etc/filesystems") next when /^#{Regexp.escape(@new_resource.mount_point)}/ enabled=false Chef::Log.debug("Found conflicting mount point #{@new_resource.mount_point} in /etc/filesystems") end end @current_resource.enabled(enabled) end def mounted? mounted = false shell_out!("mount").stdout.each_line do |line| if network_device? device_details = device_fstab.split(":") search_device = device_details[1] else search_device = device_fstab_regex end case line when /#{search_device}\s+#{Regexp.escape(@new_resource.mount_point)}/ mounted = true Chef::Log.debug("Special device #{device_logstring} mounted as #{@new_resource.mount_point}") when /^[\/\w]+\s+#{Regexp.escape(@new_resource.mount_point)}\s+/ mounted = false Chef::Log.debug("Found conflicting mount point #{@new_resource.mount_point} in /etc/fstab") end end @current_resource.mounted(mounted) end def mount_fs unless @current_resource.mounted mountable? command = "mount -v #{@new_resource.fstype}" if !(@new_resource.options.nil? || @new_resource.options.empty?) command << " -o #{@new_resource.options.join(',')}" end command << case @new_resource.device_type when :device " #{device_real}" when :label " -L #{@new_resource.device}" when :uuid " -U #{@new_resource.device}" end command << " #{@new_resource.mount_point}" shell_out!(command) Chef::Log.debug("#{@new_resource} is mounted at #{@new_resource.mount_point}") else Chef::Log.debug("#{@new_resource} is already mounted at #{@new_resource.mount_point}") end end def remount_command if !(@new_resource.options.nil? || @new_resource.options.empty?) return "mount -o remount,#{@new_resource.options.join(',')} #{@new_resource.device} #{@new_resource.mount_point}" else return "mount -o remount #{@new_resource.device} #{@new_resource.mount_point}" end end def enable_fs if @current_resource.enabled && mount_options_unchanged? Chef::Log.debug("#{@new_resource} is already enabled - nothing to do") return nil end if @current_resource.enabled # The current options don't match what we have, so # disable, then enable. disable_fs end ::File.open("/etc/filesystems", "a") do |fstab| fstab.puts("#{@new_resource.mount_point}:") if network_device? device_details = device_fstab.split(":") fstab.puts("\tdev\t\t= #{device_details[1]}") fstab.puts("\tnodename\t\t= #{device_details[0]}") else fstab.puts("\tdev\t\t= #{device_fstab}") end fstab.puts("\tvfs\t\t= #{@new_resource.fstype}") fstab.puts("\tmount\t\t= false") fstab.puts "\toptions\t\t= #{@new_resource.options.join(',')}" unless @new_resource.options.nil? || @new_resource.options.empty? Chef::Log.debug("#{@new_resource} is enabled at #{@new_resource.mount_point}") end end def disable_fs contents = [] if @current_resource.enabled found_device = false ::File.open("/etc/filesystems", "r").each_line do |line| case line when /^\/.+:\s*$/ if line =~ /#{Regexp.escape(@new_resource.mount_point)}+:/ found_device = true else found_device = false end end if !found_device contents << line end end ::File.open("/etc/filesystems", "w") do |fstab| contents.each { |line| fstab.puts line} end else Chef::Log.debug("#{@new_resource} is not enabled - nothing to do") end end end end end end chef-11.8.2/lib/chef/provider/mount/windows.rb0000644000004100000410000000557012254362222021235 0ustar www-datawww-data# # Author:: Doug MacEachern () # Copyright:: Copyright (c) 2010 VMware, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/mount' if RUBY_PLATFORM =~ /mswin|mingw32|windows/ require 'chef/util/windows/net_use' require 'chef/util/windows/volume' end class Chef class Provider class Mount class Windows < Chef::Provider::Mount def is_volume(name) name =~ /^\\\\\?\\Volume\{[\w-]+\}\\$/ ? true : false end def initialize(new_resource, run_context) super @mount = nil end def load_current_resource if is_volume(@new_resource.device) @mount = Chef::Util::Windows::Volume.new(@new_resource.name) else #assume network drive @mount = Chef::Util::Windows::NetUse.new(@new_resource.name) end @current_resource = Chef::Resource::Mount.new(@new_resource.name) @current_resource.mount_point(@new_resource.mount_point) Chef::Log.debug("Checking for mount point #{@current_resource.mount_point}") begin @current_resource.device(@mount.device) Chef::Log.debug("#{@current_resource.device} mounted on #{@new_resource.mount_point}") @current_resource.mounted(true) rescue ArgumentError => e @current_resource.mounted(false) Chef::Log.debug("#{@new_resource.mount_point} is not mounted: #{e.message}") end end def mount_fs unless @current_resource.mounted @mount.add(:remote => @new_resource.device, :username => @new_resource.username, :domainname => @new_resource.domain, :password => @new_resource.password) Chef::Log.debug("#{@new_resource} is mounted at #{@new_resource.mount_point}") else Chef::Log.debug("#{@new_resource} is already mounted at #{@new_resource.mount_point}") end end def umount_fs if @current_resource.mounted @mount.delete Chef::Log.debug("#{@new_resource} is no longer mounted at #{@new_resource.mount_point}") else Chef::Log.debug("#{@new_resource} is not mounted at #{@new_resource.mount_point}") end end end end end end chef-11.8.2/lib/chef/provider/package.rb0000644000004100000410000002175112254362222017773 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/mixin/command' require 'chef/log' require 'chef/file_cache' require 'chef/platform' class Chef class Provider class Package < Chef::Provider include Chef::Mixin::Command attr_accessor :candidate_version def initialize(new_resource, run_context) super @candidate_version = nil end def whyrun_supported? true end def load_current_resource end def define_resource_requirements requirements.assert(:install) do |a| a.assertion { ((@new_resource.version != nil) && !(target_version_already_installed?)) \ || !(@current_resource.version.nil? && candidate_version.nil?) } a.failure_message(Chef::Exceptions::Package, "No version specified, and no candidate version available for #{@new_resource.package_name}") a.whyrun("Assuming a repository that offers #{@new_resource.package_name} would have been configured") end requirements.assert(:upgrade) do |a| # Can't upgrade what we don't have a.assertion { !(@current_resource.version.nil? && candidate_version.nil?) } a.failure_message(Chef::Exceptions::Package, "No candidate version available for #{@new_resource.package_name}") a.whyrun("Assuming a repository that offers #{@new_resource.package_name} would have been configured") end end def action_install # If we specified a version, and it's not the current version, move to the specified version if !@new_resource.version.nil? && !(target_version_already_installed?) install_version = @new_resource.version # If it's not installed at all, install it elsif @current_resource.version.nil? install_version = candidate_version else Chef::Log.debug("#{@new_resource} is already installed - nothing to do") return end # We need to make sure we handle the preseed file if @new_resource.response_file if preseed_file = get_preseed_file(@new_resource.package_name, install_version) converge_by("preseed package #{@new_resource.package_name}") do preseed_package(preseed_file) end end end description = install_version ? "version #{install_version} of" : "" converge_by("install #{description} package #{@new_resource.package_name}") do @new_resource.version(install_version) install_package(@new_resource.package_name, install_version) end end def action_upgrade if candidate_version.nil? Chef::Log.debug("#{@new_resource} no candidate version - nothing to do") elsif @current_resource.version == candidate_version Chef::Log.debug("#{@new_resource} is at the latest version - nothing to do") else @new_resource.version(candidate_version) orig_version = @current_resource.version || "uninstalled" converge_by("upgrade package #{@new_resource.package_name} from #{orig_version} to #{candidate_version}") do upgrade_package(@new_resource.package_name, candidate_version) Chef::Log.info("#{@new_resource} upgraded from #{orig_version} to #{candidate_version}") end end end def action_remove if removing_package? description = @new_resource.version ? "version #{@new_resource.version} of " : "" converge_by("remove #{description} package #{@current_resource.package_name}") do remove_package(@current_resource.package_name, @new_resource.version) Chef::Log.info("#{@new_resource} removed") end else Chef::Log.debug("#{@new_resource} package does not exist - nothing to do") end end def removing_package? if @current_resource.version.nil? false # nothing to remove elsif @new_resource.version.nil? true # remove any version of a package elsif @new_resource.version == @current_resource.version true # remove the version we have else false # we don't have the version we want to remove end end def action_purge if removing_package? description = @new_resource.version ? "version #{@new_resource.version} of" : "" converge_by("purge #{description} package #{@current_resource.package_name}") do purge_package(@current_resource.package_name, @new_resource.version) Chef::Log.info("#{@new_resource} purged") end end end def action_reconfig if @current_resource.version == nil then Chef::Log.debug("#{@new_resource} is NOT installed - nothing to do") return end unless @new_resource.response_file then Chef::Log.debug("#{@new_resource} no response_file provided - nothing to do") return end if preseed_file = get_preseed_file(@new_resource.package_name, @current_resource.version) converge_by("reconfigure package #{@new_resource.package_name}") do preseed_package(preseed_file) reconfig_package(@new_resource.package_name, @current_resource.version) Chef::Log.info("#{@new_resource} reconfigured") end else Chef::Log.debug("#{@new_resource} preseeding has not changed - nothing to do") end end def install_package(name, version) raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :install" end def upgrade_package(name, version) raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :upgrade" end def remove_package(name, version) raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :remove" end def purge_package(name, version) raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :purge" end def preseed_package(file) raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support pre-seeding package install/upgrade instructions" end def reconfig_package(name, version) raise( Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :reconfig" ) end def get_preseed_file(name, version) resource = preseed_resource(name, version) resource.run_action(:create) Chef::Log.debug("#{@new_resource} fetched preseed file to #{resource.path}") if resource.updated_by_last_action? resource.path else false end end def preseed_resource(name, version) # A directory in our cache to store this cookbook's preseed files in file_cache_dir = Chef::FileCache.create_cache_path("preseed/#{@new_resource.cookbook_name}") # The full path where the preseed file will be stored cache_seed_to = "#{file_cache_dir}/#{name}-#{version}.seed" Chef::Log.debug("#{@new_resource} fetching preseed file to #{cache_seed_to}") if template_available?(@new_resource.response_file) Chef::Log.debug("#{@new_resource} fetching preseed file via Template") remote_file = Chef::Resource::Template.new(cache_seed_to, run_context) elsif cookbook_file_available?(@new_resource.response_file) Chef::Log.debug("#{@new_resource} fetching preseed file via cookbook_file") remote_file = Chef::Resource::CookbookFile.new(cache_seed_to, run_context) else message = "No template or cookbook file found for response file #{@new_resource.response_file}" raise Chef::Exceptions::FileNotFound, message end remote_file.cookbook_name = @new_resource.cookbook_name remote_file.source(@new_resource.response_file) remote_file.backup(false) remote_file end def expand_options(options) options ? " #{options}" : "" end def target_version_already_installed? @new_resource.version == @current_resource.version end private def template_available?(path) run_context.has_template_in_cookbook?(@new_resource.cookbook_name, path) end def cookbook_file_available?(path) run_context.has_cookbook_file_in_cookbook?(@new_resource.cookbook_name, path) end end end end chef-11.8.2/lib/chef/provider/group.rb0000644000004100000410000001135512254362222017533 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 OpsCode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider' require 'chef/mixin/command' require 'etc' class Chef class Provider class Group < Chef::Provider include Chef::Mixin::Command attr_accessor :group_exists attr_accessor :change_desc def whyrun_supported? true end def initialize(new_resource, run_context) super @group_exists = true end def load_current_resource @current_resource = Chef::Resource::Group.new(@new_resource.name) @current_resource.group_name(@new_resource.group_name) group_info = nil begin group_info = Etc.getgrnam(@new_resource.group_name) rescue ArgumentError => e @group_exists = false Chef::Log.debug("#{@new_resource} group does not exist") end if group_info @new_resource.gid(group_info.gid) unless @new_resource.gid @current_resource.gid(group_info.gid) @current_resource.members(group_info.mem) end @current_resource end def define_resource_requirements requirements.assert(:modify) do |a| a.assertion { @group_exists } a.failure_message(Chef::Exceptions::Group, "Cannot modify #{@new_resource} - group does not exist!") a.whyrun("Group #{@new_resource} does not exist. Unless it would have been created earlier in this run, this attempt to modify it would fail.") end end # Check to see if a group needs any changes. Populate # @change_desc with a description of why a change must occur # # ==== Returns # :: If a change is required # :: If a change is not required def compare_group @change_desc = nil if @new_resource.gid != @current_resource.gid @change_desc = "change gid #{@current_resource.gid} to #{@new_resource.gid}" return true end if(@new_resource.append) missing_members = [] @new_resource.members.each do |member| next if @current_resource.members.include?(member) missing_members << member end if missing_members.length > 0 @change_desc = "add missing member(s): #{missing_members.join(", ")}" return true end else if @new_resource.members != @current_resource.members @change_desc = "replace group members with new list of members" return true end end return false end def action_create case @group_exists when false converge_by("create #{@new_resource}") do create_group Chef::Log.info("#{@new_resource} created") end else if compare_group converge_by(["alter group #{@new_resource}", @change_desc ]) do manage_group Chef::Log.info("#{@new_resource} altered") end end end end def action_remove if @group_exists converge_by("remove group #{@new_resource}") do remove_group Chef::Log.info("#{@new_resource} removed") end end end def action_manage if @group_exists && compare_group converge_by(["manage group #{@new_resource}", @change_desc]) do manage_group Chef::Log.info("#{@new_resource} managed") end end end def action_modify if compare_group converge_by(["modify group #{@new_resource}", @change_desc]) do manage_group Chef::Log.info("#{@new_resource} modified") end end end def create_group raise NotImplementedError, "subclasses of Chef::Provider::Group should define #create_group" end def manage_group raise NotImplementedError, "subclasses of Chef::Provider::Group should define #manage_group" end def remove_group raise NotImplementedError, "subclasses of Chef::Provider::Group should define #remove_group" end end end end chef-11.8.2/lib/chef/provider/cookbook_file/0000755000004100000410000000000012254362222020652 5ustar www-datawww-datachef-11.8.2/lib/chef/provider/cookbook_file/content.rb0000644000004100000410000000324012254362222022650 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/file_content_management/content_base' require 'chef/file_content_management/tempfile' class Chef class Provider class CookbookFile class Content < Chef::FileContentManagement::ContentBase private def file_for_provider cookbook = run_context.cookbook_collection[resource_cookbook] file_cache_location = cookbook.preferred_filename_on_disk_location(run_context.node, :files, @new_resource.source, @new_resource.path) if file_cache_location.nil? nil else tempfile = Chef::FileContentManagement::Tempfile.new(@new_resource).tempfile tempfile.close Chef::Log.debug("#{@new_resource} staging #{file_cache_location} to #{tempfile.path}") FileUtils.cp(file_cache_location, tempfile.path) tempfile end end def resource_cookbook @new_resource.cookbook || @new_resource.cookbook_name end end end end end chef-11.8.2/lib/chef/provider/subversion.rb0000644000004100000410000002011312254362222020566 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # #TODO subversion and git should both extend from a base SCM provider. require 'chef/log' require 'chef/provider' require 'chef/mixin/command' require 'fileutils' class Chef class Provider class Subversion < Chef::Provider SVN_INFO_PATTERN = /^([\w\s]+): (.+)$/ include Chef::Mixin::Command def whyrun_supported? true end def load_current_resource @current_resource = Chef::Resource::Subversion.new(@new_resource.name) unless [:export, :force_export].include?(Array(@new_resource.action).first) if current_revision = find_current_revision @current_resource.revision current_revision end end end def define_resource_requirements requirements.assert(:all_actions) do |a| # Make sure the parent dir exists, or else fail. # for why run, print a message explaining the potential error. parent_directory = ::File.dirname(@new_resource.destination) a.assertion { ::File.directory?(parent_directory) } a.failure_message(Chef::Exceptions::MissingParentDirectory, "Cannot clone #{@new_resource} to #{@new_resource.destination}, the enclosing directory #{parent_directory} does not exist") a.whyrun("Directory #{parent_directory} does not exist, assuming it would have been created") end end def action_checkout if target_dir_non_existent_or_empty? converge_by("perform checkout of #{@new_resource.repository} into #{@new_resource.destination}") do run_command(run_options(:command => checkout_command)) end else Chef::Log.debug "#{@new_resource} checkout destination #{@new_resource.destination} already exists or is a non-empty directory - nothing to do" end end def action_export if target_dir_non_existent_or_empty? action_force_export else Chef::Log.debug "#{@new_resource} export destination #{@new_resource.destination} already exists or is a non-empty directory - nothing to do" end end def action_force_export converge_by("export #{@new_resource.repository} into #{@new_resource.destination}") do run_command(run_options(:command => export_command)) end end def action_sync assert_target_directory_valid! if ::File.exist?(::File.join(@new_resource.destination, ".svn")) current_rev = find_current_revision Chef::Log.debug "#{@new_resource} current revision: #{current_rev} target revision: #{revision_int}" unless current_revision_matches_target_revision? converge_by("sync #{@new_resource.destination} from #{@new_resource.repository}") do run_command(run_options(:command => sync_command)) Chef::Log.info "#{@new_resource} updated to revision: #{revision_int}" end end else action_checkout end end def sync_command c = scm :update, @new_resource.svn_arguments, verbose, authentication, "-r#{revision_int}", @new_resource.destination Chef::Log.debug "#{@new_resource} updated working copy #{@new_resource.destination} to revision #{@new_resource.revision}" c end def checkout_command c = scm :checkout, @new_resource.svn_arguments, verbose, authentication, "-r#{revision_int}", @new_resource.repository, @new_resource.destination Chef::Log.info "#{@new_resource} checked out #{@new_resource.repository} at revision #{@new_resource.revision} to #{@new_resource.destination}" c end def export_command args = ["--force"] args << @new_resource.svn_arguments << verbose << authentication << "-r#{revision_int}" << @new_resource.repository << @new_resource.destination c = scm :export, *args Chef::Log.info "#{@new_resource} exported #{@new_resource.repository} at revision #{@new_resource.revision} to #{@new_resource.destination}" c end # If the specified revision isn't an integer ("HEAD" for example), look # up the revision id by asking the server # If the specified revision is an integer, trust it. def revision_int @revision_int ||= begin if @new_resource.revision =~ /^\d+$/ @new_resource.revision else command = scm(:info, @new_resource.repository, @new_resource.svn_info_args, authentication, "-r#{@new_resource.revision}") status, svn_info, error_message = output_of_command(command, run_options) handle_command_failures(status, "STDOUT: #{svn_info}\nSTDERR: #{error_message}") extract_revision_info(svn_info) end end end alias :revision_slug :revision_int def find_current_revision return nil unless ::File.exist?(::File.join(@new_resource.destination, ".svn")) command = scm(:info) status, svn_info, error_message = output_of_command(command, run_options(:cwd => cwd)) unless [0,1].include?(status.exitstatus) handle_command_failures(status, "STDOUT: #{svn_info}\nSTDERR: #{error_message}") end extract_revision_info(svn_info) end def current_revision_matches_target_revision? (!@current_resource.revision.nil?) && (revision_int.strip.to_i == @current_resource.revision.strip.to_i) end def run_options(run_opts={}) run_opts[:user] = @new_resource.user if @new_resource.user run_opts[:group] = @new_resource.group if @new_resource.group run_opts[:timeout] = @new_resource.timeout if @new_resource.timeout run_opts end private def cwd @new_resource.destination end def verbose "-q" end def extract_revision_info(svn_info) repo_attrs = svn_info.lines.inject({}) do |attrs, line| if line =~ SVN_INFO_PATTERN property, value = $1, $2 attrs[property] = value end attrs end rev = (repo_attrs['Last Changed Rev'] || repo_attrs['Revision']) raise "Could not parse `svn info` data: #{svn_info}" if repo_attrs.empty? Chef::Log.debug "#{@new_resource} resolved revision #{@new_resource.revision} to #{rev}" rev end # If a username is configured for the SCM, return the command-line # switches for that. Note that we don't need to return the password # switch, since Capistrano will check for that prompt in the output # and will respond appropriately. def authentication return "" unless @new_resource.svn_username result = "--username #{@new_resource.svn_username} " result << "--password #{@new_resource.svn_password} " result end def scm(*args) ['svn', *args].compact.join(" ") end def target_dir_non_existent_or_empty? !::File.exist?(@new_resource.destination) || Dir.entries(@new_resource.destination).sort == ['.','..'] end def assert_target_directory_valid! target_parent_directory = ::File.dirname(@new_resource.destination) unless ::File.directory?(target_parent_directory) msg = "Cannot clone #{@new_resource} to #{@new_resource.destination}, the enclosing directory #{target_parent_directory} does not exist" raise Chef::Exceptions::MissingParentDirectory, msg end end end end end chef-11.8.2/lib/chef/provider/service/0000755000004100000410000000000012254362222017505 5ustar www-datawww-datachef-11.8.2/lib/chef/provider/service/insserv.rb0000644000004100000410000000316412254362222021527 0ustar www-datawww-data# # Author:: Bryan McLellan # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/service' require 'chef/provider/service/init' require 'chef/mixin/command' class Chef class Provider class Service class Insserv < Chef::Provider::Service::Init def load_current_resource super # Look for a /etc/rc.*/SnnSERVICE link to signifiy that the service would be started in a runlevel if Dir.glob("/etc/rc**/S*#{@current_resource.service_name}").empty? @current_resource.enabled false else @current_resource.enabled true end @current_resource end def enable_service() run_command(:command => "/sbin/insserv -r -f #{@new_resource.service_name}") run_command(:command => "/sbin/insserv -d -f #{@new_resource.service_name}") end def disable_service() run_command(:command => "/sbin/insserv -r -f #{@new_resource.service_name}") end end end end end chef-11.8.2/lib/chef/provider/service/redhat.rb0000644000004100000410000000506712254362222021311 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/service' require 'chef/provider/service/init' require 'chef/mixin/shell_out' class Chef class Provider class Service class Redhat < Chef::Provider::Service::Init include Chef::Mixin::ShellOut CHKCONFIG_ON = /\d:on/ CHKCONFIG_MISSING = /No such/ def initialize(new_resource, run_context) super @init_command = "/sbin/service #{@new_resource.service_name}" @new_resource.supports[:status] = true @service_missing = false end def define_resource_requirements shared_resource_requirements requirements.assert(:all_actions) do |a| chkconfig_file = "/sbin/chkconfig" a.assertion { ::File.exists? chkconfig_file } a.failure_message Chef::Exceptions::Service, "#{chkconfig_file} does not exist!" end requirements.assert(:start, :enable, :reload, :restart) do |a| a.assertion { !@service_missing } a.failure_message Chef::Exceptions::Service, "#{@new_resource}: unable to locate the init.d script!" a.whyrun "Assuming service would be disabled. The init script is not presently installed." end end def load_current_resource super if ::File.exists?("/sbin/chkconfig") chkconfig = shell_out!("/sbin/chkconfig --list #{@current_resource.service_name}", :returns => [0,1]) @current_resource.enabled(!!(chkconfig.stdout =~ CHKCONFIG_ON)) @service_missing = !!(chkconfig.stderr =~ CHKCONFIG_MISSING) end @current_resource end def enable_service() shell_out! "/sbin/chkconfig #{@new_resource.service_name} on" end def disable_service() shell_out! "/sbin/chkconfig #{@new_resource.service_name} off" end end end end end chef-11.8.2/lib/chef/provider/service/debian.rb0000644000004100000410000001633412254362222021263 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/service' require 'chef/provider/service/init' require 'chef/mixin/command' class Chef class Provider class Service class Debian < Chef::Provider::Service::Init UPDATE_RC_D_ENABLED_MATCHES = /\/rc[\dS].d\/S|not installed/i UPDATE_RC_D_PRIORITIES = /\/rc([\dS]).d\/([SK])(\d\d)/i def load_current_resource super @priority_success = true @rcd_status = nil @current_resource.priority(get_priority) @current_resource.enabled(service_currently_enabled?(@current_resource.priority)) @current_resource end def define_resource_requirements # do not call super here, inherit only shared_requirements shared_resource_requirements requirements.assert(:all_actions) do |a| update_rcd = "/usr/sbin/update-rc.d" a.assertion { ::File.exists? update_rcd } a.failure_message Chef::Exceptions::Service, "#{update_rcd} does not exist!" # no whyrun recovery - this is a base system component of debian # distros and must be present end requirements.assert(:all_actions) do |a| a.assertion { @priority_success } a.failure_message Chef::Exceptions::Service, "/usr/sbin/update-rc.d -n -f #{@current_resource.service_name} failed - #{@rcd_status.inspect}" # This can happen if the service is not yet installed,so we'll fake it. a.whyrun ["Unable to determine priority of service, assuming service would have been correctly installed earlier in the run.", "Assigning temporary priorities to continue.", "If this service is not properly installed prior to this point, this will fail."] do temp_priorities = {"6"=>[:stop, "20"], "0"=>[:stop, "20"], "1"=>[:stop, "20"], "2"=>[:start, "20"], "3"=>[:start, "20"], "4"=>[:start, "20"], "5"=>[:start, "20"]} @current_resource.priority(temp_priorities) end end end def get_priority priority = {} @rcd_status = popen4("/usr/sbin/update-rc.d -n -f #{@current_resource.service_name} remove") do |pid, stdin, stdout, stderr| [stdout, stderr].each do |iop| iop.each_line do |line| if UPDATE_RC_D_PRIORITIES =~ line # priority[runlevel] = [ S|K, priority ] # S = Start, K = Kill # debian runlevels: 0 Halt, 1 Singleuser, 2 Multiuser, 3-5 == 2, 6 Reboot priority[$1] = [($2 == "S" ? :start : :stop), $3] end if line =~ UPDATE_RC_D_ENABLED_MATCHES enabled = true end end end end # Reduce existing priority back to an integer if appropriate, picking # runlevel 2 as a baseline if priority[2] && [2..5].all? { |runlevel| priority[runlevel] == priority[2] } priority = priority[2].last end unless @rcd_status.exitstatus == 0 @priority_success = false end priority end def service_currently_enabled?(priority) enabled = false priority.each { |runlevel, arguments| Chef::Log.debug("#{@new_resource} runlevel #{runlevel}, action #{arguments[0]}, priority #{arguments[1]}") # if we are in a update-rc.d default startup runlevel && we start in this runlevel if (2..5).include?(runlevel.to_i) && arguments[0] == :start enabled = true end } enabled end # Override method from parent to ensure priority is up-to-date def action_enable if @current_resource.enabled && @current_resource.priority == @new_resource.priority Chef::Log.debug("#{@new_resource} already enabled - nothing to do") else converge_by("enable service #{@new_resource}") do enable_service Chef::Log.info("#{@new_resource} enabled") end end load_new_resource_state @new_resource.enabled(true) end def enable_service if @new_resource.priority.is_a? Integer run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove") run_command(:command => "/usr/sbin/update-rc.d #{@new_resource.service_name} defaults #{@new_resource.priority} #{100 - @new_resource.priority}") elsif @new_resource.priority.is_a? Hash # we call the same command regardless of we're enabling or disabling # users passing a Hash are responsible for setting their own start priorities set_priority else # No priority, go with update-rc.d defaults run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove") run_command(:command => "/usr/sbin/update-rc.d #{@new_resource.service_name} defaults") end end def disable_service if @new_resource.priority.is_a? Integer # Stop processes in reverse order of start using '100 - start_priority' run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove") run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} stop #{100 - @new_resource.priority} 2 3 4 5 .") elsif @new_resource.priority.is_a? Hash # we call the same command regardless of we're enabling or disabling # users passing a Hash are responsible for setting their own stop priorities set_priority else # no priority, using '100 - 20 (update-rc.d default)' to stop in reverse order of start run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove") run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} stop 80 2 3 4 5 .") end end def set_priority args = "" @new_resource.priority.each do |level, o| action = o[0] priority = o[1] args += "#{action} #{priority} #{level} . " end run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove") run_command(:command => "/usr/sbin/update-rc.d #{@new_resource.service_name} #{args}") end end end end end chef-11.8.2/lib/chef/provider/service/invokercd.rb0000644000004100000410000000206212254362222022016 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/service' require 'chef/provider/service/init' require 'chef/mixin/command' class Chef class Provider class Service class Invokercd < Chef::Provider::Service::Init def initialize(new_resource, run_context) super @init_command = "/usr/sbin/invoke-rc.d #{@new_resource.service_name}" end end end end end chef-11.8.2/lib/chef/provider/service/upstart.rb0000644000004100000410000002207612254362222021543 0ustar www-datawww-data# # Author:: Bryan McLellan # Copyright:: Copyright (c) 2010 Bryan McLellan # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/service' require 'chef/provider/service/simple' require 'chef/mixin/command' require 'chef/util/file_edit' class Chef class Provider class Service class Upstart < Chef::Provider::Service::Simple UPSTART_STATE_FORMAT = /\w+ \(?(\w+)\)?[\/ ](\w+)/ # Upstart does more than start or stop a service, creating multiple 'states' [1] that a service can be in. # In chef, when we ask a service to start, we expect it to have started before performing the next step # since we have top down dependencies. Which is to say we may follow witha resource next that requires # that service to be running. According to [2] we can trust that sending a 'goal' such as start will not # return until that 'goal' is reached, or some error has occured. # # [1] http://upstart.ubuntu.com/wiki/JobStates # [2] http://www.netsplit.com/2008/04/27/upstart-05-events/ def initialize(new_resource, run_context) # TODO: re-evaluate if this is needed after integrating cookbook fix raise ArgumentError, "run_context cannot be nil" unless run_context super run_context.node @job = @new_resource.service_name if @new_resource.parameters @new_resource.parameters.each do |key, value| @job << " #{key}=#{value}" end end platform, version = Chef::Platform.find_platform_and_version(run_context.node) if platform == "ubuntu" && (8.04..9.04).include?(version.to_f) @upstart_job_dir = "/etc/event.d" @upstart_conf_suffix = "" else @upstart_job_dir = "/etc/init" @upstart_conf_suffix = ".conf" end @command_success = true # new_resource.status_command= false, means upstart used @config_file_found = true @upstart_command_success = true end def define_resource_requirements # Do not call super, only call shared requirements shared_resource_requirements requirements.assert(:all_actions) do |a| if !@command_success whyrun_msg = @new_resource.status_command ? "Provided status command #{@new_resource.status_command} failed." : "Could not determine upstart state for service" end a.assertion { @command_success } # no failure here, just document the assumptions made. a.whyrun "#{whyrun_msg} Assuming service installed and not running." end requirements.assert(:all_actions) do |a| a.assertion { @config_file_found } # no failure here, just document the assumptions made. a.whyrun "Could not find #{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}. Assuming service is disabled." end end def load_current_resource @current_resource = Chef::Resource::Service.new(@new_resource.name) @current_resource.service_name(@new_resource.service_name) # Get running/stopped state # We do not support searching for a service via ps when using upstart since status is a native # upstart function. We will however support status_command in case someone wants to do something special. if @new_resource.status_command Chef::Log.debug("#{@new_resource} you have specified a status command, running..") begin if run_command_with_systems_locale(:command => @new_resource.status_command) == 0 @current_resource.running true end rescue Chef::Exceptions::Exec @command_success = false @current_resource.running false nil end else begin if upstart_state == "running" @current_resource.running true else @current_resource.running false end rescue Chef::Exceptions::Exec @command_success = false @current_resource.running false nil end end # Get enabled/disabled state by reading job configuration file if ::File.exists?("#{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}") Chef::Log.debug("#{@new_resource} found #{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}") ::File.open("#{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}",'r') do |file| while line = file.gets case line when /^start on/ Chef::Log.debug("#{@new_resource} enabled: #{line.chomp}") @current_resource.enabled true break when /^#start on/ Chef::Log.debug("#{@new_resource} disabled: #{line.chomp}") @current_resource.enabled false break end end end else @config_file_found = false Chef::Log.debug("#{@new_resource} did not find #{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}") @current_resource.enabled false end @current_resource end def start_service # Calling start on a service that is already started will return 1 # Our 'goal' when we call start is to ensure the service is started if @current_resource.running Chef::Log.debug("#{@new_resource} already running, not starting") else if @new_resource.start_command super else run_command_with_systems_locale(:command => "/sbin/start #{@job}") end end end def stop_service # Calling stop on a service that is already stopped will return 1 # Our 'goal' when we call stop is to ensure the service is stopped unless @current_resource.running Chef::Log.debug("#{@new_resource} not running, not stopping") else if @new_resource.stop_command super else run_command_with_systems_locale(:command => "/sbin/stop #{@job}") end end end def restart_service if @new_resource.restart_command super # Upstart always provides restart functionality so we don't need to mimic it with stop/sleep/start. # Older versions of upstart would fail on restart if the service was currently stopped, check for that. LP:430883 else if @current_resource.running run_command_with_systems_locale(:command => "/sbin/restart #{@job}") else start_service end end end def reload_service if @new_resource.reload_command super else # upstart >= 0.6.3-4 supports reload (HUP) run_command_with_systems_locale(:command => "/sbin/reload #{@job}") end end # https://bugs.launchpad.net/upstart/+bug/94065 def enable_service Chef::Log.debug("#{@new_resource} upstart lacks inherent support for enabling services, editing job config file") conf = Chef::Util::FileEdit.new("#{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}") conf.search_file_replace(/^#start on/, "start on") conf.write_file end def disable_service Chef::Log.debug("#{@new_resource} upstart lacks inherent support for disabling services, editing job config file") conf = Chef::Util::FileEdit.new("#{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}") conf.search_file_replace(/^start on/, "#start on") conf.write_file end def upstart_state command = "/sbin/status #{@job}" status = popen4(command) do |pid, stdin, stdout, stderr| stdout.each_line do |line| # rsyslog stop/waiting # service goal/state # OR # rsyslog (stop) waiting # service (goal) state line =~ UPSTART_STATE_FORMAT data = Regexp.last_match return data[2] end end end end end end end chef-11.8.2/lib/chef/provider/service/simple.rb0000644000004100000410000001536012254362222021330 0ustar www-datawww-data# # Author:: Mathieu Sauve-Frankel # Copyright:: Copyright (c) 2009 Mathieu Sauve-Frankel # License:: Apache License, Version 2.0 # # 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. # require 'chef/mixin/shell_out' require 'chef/provider/service' require 'chef/mixin/command' class Chef class Provider class Service class Simple < Chef::Provider::Service include Chef::Mixin::ShellOut def load_current_resource @current_resource = Chef::Resource::Service.new(@new_resource.name) @current_resource.service_name(@new_resource.service_name) @status_load_success = true @ps_command_failed = false determine_current_status! @current_resource end def whyrun_supported? true end def shared_resource_requirements super requirements.assert(:all_actions) do |a| a.assertion { @status_load_success } a.whyrun ["Service status not available. Assuming a prior action would have installed the service.", "Assuming status of not running."] end end def define_resource_requirements # FIXME? need reload from service.rb shared_resource_requirements requirements.assert(:start) do |a| a.assertion { @new_resource.start_command } a.failure_message Chef::Exceptions::Service, "#{self.to_s} requires that start_command be set" end requirements.assert(:stop) do |a| a.assertion { @new_resource.stop_command } a.failure_message Chef::Exceptions::Service, "#{self.to_s} requires that stop_command be set" end requirements.assert(:restart) do |a| a.assertion { @new_resource.restart_command || ( @new_resource.start_command && @new_resource.stop_command ) } a.failure_message Chef::Exceptions::Service, "#{self.to_s} requires a restart_command or both start_command and stop_command be set in order to perform a restart" end requirements.assert(:reload) do |a| a.assertion { @new_resource.reload_command } a.failure_message Chef::Exceptions::UnsupportedAction, "#{self.to_s} requires a reload_command be set in order to perform a reload" end requirements.assert(:all_actions) do |a| a.assertion { @new_resource.status_command or @new_resource.supports[:status] or (!ps_cmd.nil? and !ps_cmd.empty?) } a.failure_message Chef::Exceptions::Service, "#{@new_resource} could not determine how to inspect the process table, please set this node's 'command.ps' attribute" end requirements.assert(:all_actions) do |a| a.assertion { !@ps_command_failed } a.failure_message Chef::Exceptions::Service, "Command #{ps_cmd} failed to execute, cannot determine service current status" end end def start_service shell_out!(@new_resource.start_command) end def stop_service shell_out!(@new_resource.stop_command) end def restart_service if @new_resource.restart_command shell_out!(@new_resource.restart_command) else stop_service sleep 1 start_service end end def reload_service shell_out!(@new_resource.reload_command) end protected def determine_current_status! if @new_resource.status_command Chef::Log.debug("#{@new_resource} you have specified a status command, running..") begin if shell_out(@new_resource.status_command).exitstatus == 0 @current_resource.running true Chef::Log.debug("#{@new_resource} is running") end rescue Mixlib::ShellOut::ShellCommandFailed, SystemCallError # ShellOut sometimes throws different types of Exceptions than ShellCommandFailed. # Temporarily catching different types of exceptions here until we get Shellout fixed. # TODO: Remove the line before one we get the ShellOut fix. @status_load_success = false @current_resource.running false nil end elsif @new_resource.supports[:status] Chef::Log.debug("#{@new_resource} supports status, running") begin if shell_out("#{default_init_command} status").exitstatus == 0 @current_resource.running true Chef::Log.debug("#{@new_resource} is running") end # ShellOut sometimes throws different types of Exceptions than ShellCommandFailed. # Temporarily catching different types of exceptions here until we get Shellout fixed. # TODO: Remove the line before one we get the ShellOut fix. rescue Mixlib::ShellOut::ShellCommandFailed, SystemCallError @status_load_success = false @current_resource.running false nil end else Chef::Log.debug "#{@new_resource} falling back to process table inspection" r = Regexp.new(@new_resource.pattern) Chef::Log.debug "#{@new_resource} attempting to match '#{@new_resource.pattern}' (#{r.inspect}) against process list" begin shell_out!(ps_cmd).stdout.each_line do |line| if r.match(line) @current_resource.running true break end end @current_resource.running false unless @current_resource.running Chef::Log.debug "#{@new_resource} running: #{@current_resource.running}" # ShellOut sometimes throws different types of Exceptions than ShellCommandFailed. # Temporarily catching different types of exceptions here until we get Shellout fixed. # TODO: Remove the line before one we get the ShellOut fix. rescue Mixlib::ShellOut::ShellCommandFailed, SystemCallError @ps_command_failed = true end end end def ps_cmd @run_context.node[:command] && @run_context.node[:command][:ps] end end end end end chef-11.8.2/lib/chef/provider/service/freebsd.rb0000644000004100000410000001463312254362222021453 0ustar www-datawww-data# # Author:: Bryan McLellan (btm@loftninjas.org) # Copyright:: Copyright (c) 2009 Bryan McLellan # License:: Apache License, Version 2.0 # # 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. # require 'chef/mixin/shell_out' require 'chef/provider/service' require 'chef/mixin/command' class Chef class Provider class Service class Freebsd < Chef::Provider::Service::Init include Chef::Mixin::ShellOut def load_current_resource @current_resource = Chef::Resource::Service.new(@new_resource.name) @current_resource.service_name(@new_resource.service_name) @rcd_script_found = true @enabled_state_found = false # Determine if we're talking about /etc/rc.d or /usr/local/etc/rc.d if ::File.exists?("/etc/rc.d/#{current_resource.service_name}") @init_command = "/etc/rc.d/#{current_resource.service_name}" elsif ::File.exists?("/usr/local/etc/rc.d/#{current_resource.service_name}") @init_command = "/usr/local/etc/rc.d/#{current_resource.service_name}" else @rcd_script_found = false return end Chef::Log.debug("#{@current_resource} found at #{@init_command}") determine_current_status! # Default to disabled if the service doesn't currently exist # at all var_name = service_enable_variable_name if ::File.exists?("/etc/rc.conf") && var_name read_rc_conf.each do |line| case line when /#{Regexp.escape(var_name)}="(\w+)"/ @enabled_state_found = true if $1 =~ /[Yy][Ee][Ss]/ @current_resource.enabled true elsif $1 =~ /[Nn][Oo][Nn]?[Oo]?[Nn]?[Ee]?/ @current_resource.enabled false end end end end unless @current_resource.enabled Chef::Log.debug("#{@new_resource.name} enable/disable state unknown") @current_resource.enabled false end @current_resource end def define_resource_requirements shared_resource_requirements requirements.assert(:start, :enable, :reload, :restart) do |a| a.assertion { @rcd_script_found } a.failure_message Chef::Exceptions::Service, "#{@new_resource}: unable to locate the rc.d script" end requirements.assert(:all_actions) do |a| a.assertion { @enabled_state_found } # for consistentcy with original behavior, this will not fail in non-whyrun mode; # rather it will silently set enabled state=>false a.whyrun "Unable to determine enabled/disabled state, assuming this will be correct for an actual run. Assuming disabled." end requirements.assert(:start, :enable, :reload, :restart) do |a| a.assertion { @rcd_script_found && service_enable_variable_name != nil } a.failure_message Chef::Exceptions::Service, "Could not find the service name in #{@init_command} and rcvar" # No recovery in whyrun mode - the init file is present but not correct. end end def start_service if @new_resource.start_command super else shell_out!("#{@init_command} faststart") end end def stop_service if @new_resource.stop_command super else shell_out!("#{@init_command} faststop") end end def restart_service if @new_resource.restart_command super elsif @new_resource.supports[:restart] shell_out!("#{@init_command} fastrestart") else stop_service sleep 1 start_service end end def read_rc_conf ::File.open("/etc/rc.conf", 'r') { |file| file.readlines } end def write_rc_conf(lines) ::File.open("/etc/rc.conf", 'w') do |file| lines.each { |line| file.puts(line) } end end # The variable name used in /etc/rc.conf for enabling this service def service_enable_variable_name # Look for name="foo" in the shell script @init_command. Use this for determining the variable name in /etc/rc.conf # corresponding to this service # For example: to enable the service mysql-server with the init command /usr/local/etc/rc.d/mysql-server, you need # to set mysql_enable="YES" in /etc/rc.conf$ if @rcd_script_found ::File.open(@init_command) do |rcscript| rcscript.each_line do |line| if line =~ /^name="?(\w+)"?/ return $1 + "_enable" end end end # some scripts support multiple instances through symlinks such as openvpn. # We should get the service name from rcvar. Chef::Log.debug("name=\"service\" not found at #{@init_command}. falling back to rcvar") sn = shell_out!("#{@init_command} rcvar").stdout[/(\w+_enable)=/, 1] return sn end # Fallback allows us to keep running in whyrun mode when # the script does not exist. @new_resource.service_name end def set_service_enable(value) lines = read_rc_conf # Remove line that set the old value lines.delete_if { |line| line =~ /#{Regexp.escape(service_enable_variable_name)}/ } # And append the line that sets the new value at the end lines << "#{service_enable_variable_name}=\"#{value}\"" write_rc_conf(lines) end def enable_service() set_service_enable("YES") unless @current_resource.enabled end def disable_service() set_service_enable("NO") if @current_resource.enabled end end end end end chef-11.8.2/lib/chef/provider/service/init.rb0000644000004100000410000000532712254362222021004 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/mixin/shell_out' require 'chef/provider/service' require 'chef/provider/service/simple' require 'chef/mixin/command' class Chef class Provider class Service class Init < Chef::Provider::Service::Simple include Chef::Mixin::ShellOut def initialize(new_resource, run_context) super @init_command = "/etc/init.d/#{@new_resource.service_name}" end def define_resource_requirements # do not call super here, inherit only shared_requirements shared_resource_requirements requirements.assert(:start, :stop, :restart, :reload) do |a| a.assertion do custom_command_for_action?(action) || ::File.exist?(default_init_command) end a.failure_message(Chef::Exceptions::Service, "#{default_init_command} does not exist!") a.whyrun("Init script '#{default_init_command}' doesn't exist, assuming a prior action would have created it.") do # blindly assume that the service exists but is stopped in why run mode: @status_load_success = false end end end def start_service if @new_resource.start_command super else shell_out!("#{default_init_command} start") end end def stop_service if @new_resource.stop_command super else shell_out!("#{default_init_command} stop") end end def restart_service if @new_resource.restart_command super elsif @new_resource.supports[:restart] shell_out!("#{default_init_command} restart") else stop_service sleep 1 start_service end end def reload_service if @new_resource.reload_command super elsif @new_resource.supports[:reload] shell_out!("#{default_init_command} reload") end end end end end end chef-11.8.2/lib/chef/provider/service/solaris.rb0000644000004100000410000000524212254362222021511 0ustar www-datawww-data# # Author:: Toomas Pelberg () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/mixin/shell_out' require 'chef/provider/service' require 'chef/mixin/command' class Chef class Provider class Service class Solaris < Chef::Provider::Service include Chef::Mixin::ShellOut def initialize(new_resource, run_context=nil) super @init_command = "/usr/sbin/svcadm" @status_command = "/bin/svcs -l" end def load_current_resource @current_resource = Chef::Resource::Service.new(@new_resource.name) @current_resource.service_name(@new_resource.service_name) unless ::File.exists? "/bin/svcs" raise Chef::Exceptions::Service, "/bin/svcs does not exist!" end @status = service_status.enabled @current_resource end def enable_service shell_out!("#{default_init_command} enable -s #{@new_resource.service_name}") end def disable_service shell_out!("#{default_init_command} disable -s #{@new_resource.service_name}") end alias_method :stop_service, :disable_service alias_method :start_service, :enable_service def reload_service shell_out!("#{default_init_command} refresh #{@new_resource.service_name}") end def restart_service ## svcadm restart doesn't supports sync(-s) option disable_service return enable_service end def service_status status = popen4("#{@status_command} #{@current_resource.service_name}") do |pid, stdin, stdout, stderr| stdout.each do |line| case line when /state\s+online/ @current_resource.enabled(true) @current_resource.running(true) end end end unless @current_resource.enabled @current_resource.enabled(false) @current_resource.running(false) end @current_resource end end end end end chef-11.8.2/lib/chef/provider/service/macosx.rb0000644000004100000410000001144012254362222021324 0ustar www-datawww-data# # Author:: Igor Afonov # Copyright:: Copyright (c) 2011 Igor Afonov # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/service' class Chef class Provider class Service class Macosx < Chef::Provider::Service::Simple include Chef::Mixin::ShellOut def self.gather_plist_dirs locations = %w{/Library/LaunchAgents /Library/LaunchDaemons /System/Library/LaunchAgents /System/Library/LaunchDaemons } locations << "#{ENV['HOME']}/Library/LaunchAgents" if ENV['HOME'] locations end PLIST_DIRS = gather_plist_dirs def load_current_resource @current_resource = Chef::Resource::Service.new(@new_resource.name) @current_resource.service_name(@new_resource.service_name) @plist_size = 0 @plist = find_service_plist set_service_status @current_resource end def define_resource_requirements #super requirements.assert(:enable) do |a| a.failure_message Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :enable" end requirements.assert(:disable) do |a| a.failure_message Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :disable" end requirements.assert(:reload) do |a| a.failure_message Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :reload" end requirements.assert(:all_actions) do |a| a.assertion { @plist_size < 2 } a.failure_message Chef::Exceptions::Service, "Several plist files match service name. Please use full service name." end requirements.assert(:all_actions) do |a| a.assertion { @plist_size > 0 } # No failrue here in original code - so we also will not # fail. Instead warn that the service is potentially missing a.whyrun "Assuming that the service would have been previously installed and is currently disabled." do @current_resource.enabled(false) @current_resource.running(false) end end end def start_service if @current_resource.running Chef::Log.debug("#{@new_resource} already running, not starting") else if @new_resource.start_command super else shell_out!("launchctl load -w '#{@plist}'", :user => @owner_uid, :group => @owner_gid) end end end def stop_service unless @current_resource.running Chef::Log.debug("#{@new_resource} not running, not stopping") else if @new_resource.stop_command super else shell_out!("launchctl unload '#{@plist}'", :user => @owner_uid, :group => @owner_gid) end end end def restart_service if @new_resource.restart_command super else stop_service sleep 1 start_service end end def set_service_status return if @plist == nil @current_resource.enabled(!@plist.nil?) if @current_resource.enabled @owner_uid = ::File.stat(@plist).uid @owner_gid = ::File.stat(@plist).gid shell_out!("launchctl list", :user => @owner_uid, :group => @owner_gid).stdout.each_line do |line| case line when /(\d+|-)\s+(?:\d+|-)\s+(.*\.?)#{@current_resource.service_name}/ pid = $1 @current_resource.running(!pid.to_i.zero?) end end else @current_resource.running(false) end end private def find_service_plist plists = PLIST_DIRS.inject([]) do |results, dir| entries = Dir.glob("#{::File.expand_path(dir)}/*#{@current_resource.service_name}*.plist") entries.any? ? results << entries : results end plists.flatten! @plist_size = plists.size plists.first end end end end end chef-11.8.2/lib/chef/provider/service/systemd.rb0000644000004100000410000000722012254362222021523 0ustar www-datawww-data# # Author:: Stephen Haynes () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/service' require 'chef/provider/service/simple' require 'chef/mixin/command' class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple def load_current_resource @current_resource = Chef::Resource::Service.new(@new_resource.name) @current_resource.service_name(@new_resource.service_name) @status_check_success = true if @new_resource.status_command Chef::Log.debug("#{@new_resource} you have specified a status command, running..") begin if run_command_with_systems_locale(:command => @new_resource.status_command) == 0 @current_resource.running(true) end rescue Chef::Exceptions::Exec @status_check_success = false @current_resource.running(false) @current_resource.enabled(false) nil end else @current_resource.running(is_active?) end @current_resource.enabled(is_enabled?) @current_resource end def define_resource_requirements shared_resource_requirements requirements.assert(:all_actions) do |a| a.assertion { @status_check_success } # We won't stop in any case, but in whyrun warn and tell what we're doing. a.whyrun ["Failed to determine status of #{@new_resource}, using command #{@new_resource.status_command}.", "Assuming service would have been installed and is disabled"] end end def start_service if @current_resource.running Chef::Log.debug("#{@new_resource} already running, not starting") else if @new_resource.start_command super else run_command_with_systems_locale(:command => "/bin/systemctl start #{@new_resource.service_name}") end end end def stop_service unless @current_resource.running Chef::Log.debug("#{@new_resource} not running, not stopping") else if @new_resource.stop_command super else run_command_with_systems_locale(:command => "/bin/systemctl stop #{@new_resource.service_name}") end end end def restart_service if @new_resource.restart_command super else run_command_with_systems_locale(:command => "/bin/systemctl restart #{@new_resource.service_name}") end end def reload_service if @new_resource.reload_command super else run_command_with_systems_locale(:command => "/bin/systemctl reload #{@new_resource.service_name}") end end def enable_service run_command_with_systems_locale(:command => "/bin/systemctl enable #{@new_resource.service_name}") end def disable_service run_command_with_systems_locale(:command => "/bin/systemctl disable #{@new_resource.service_name}") end def is_active? run_command_with_systems_locale({:command => "/bin/systemctl is-active #{@new_resource.service_name}", :ignore_failure => true}) == 0 end def is_enabled? run_command_with_systems_locale({:command => "/bin/systemctl is-enabled #{@new_resource.service_name}", :ignore_failure => true}) == 0 end end chef-11.8.2/lib/chef/provider/service/gentoo.rb0000644000004100000410000000443712254362222021335 0ustar www-datawww-data# # Author:: Lee Jensen () # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/service' require 'chef/mixin/command' class Chef::Provider::Service::Gentoo < Chef::Provider::Service::Init def load_current_resource @new_resource.supports[:status] = true @new_resource.supports[:restart] = true @found_script = false super @current_resource.enabled( Dir.glob("/etc/runlevels/**/#{@current_resource.service_name}").any? do |file| @found_script = true exists = ::File.exists? file readable = ::File.readable? file Chef::Log.debug "#{@new_resource} exists: #{exists}, readable: #{readable}" exists and readable end ) Chef::Log.debug "#{@new_resource} enabled: #{@current_resource.enabled}" @current_resource end def define_resource_requirements requirements.assert(:all_actions) do |a| a.assertion { ::File.exists?("/sbin/rc-update") } a.failure_message Chef::Exceptions::Service, "/sbin/rc-update does not exist" # no whyrun recovery -t his is a core component whose presence is # unlikely to be affected by what we do in the course of a chef run end requirements.assert(:all_actions) do |a| a.assertion { @found_script } # No failure, just informational output from whyrun a.whyrun "Could not find service #{@new_resource.service_name} under any runlevel" end end def enable_service() run_command(:command => "/sbin/rc-update add #{@new_resource.service_name} default") end def disable_service() run_command(:command => "/sbin/rc-update del #{@new_resource.service_name} default") end end chef-11.8.2/lib/chef/provider/service/windows.rb0000644000004100000410000001175612254362222021536 0ustar www-datawww-data# # Author:: Nuo Yan # Author:: Bryan McLellan # Author:: Seth Chisamore # Copyright:: Copyright (c) 2010-2011 Opscode, Inc # License:: Apache License, Version 2.0 # # 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. # require 'chef/mixin/shell_out' require 'chef/provider/service/simple' if RUBY_PLATFORM =~ /mswin|mingw32|windows/ require 'win32/service' end class Chef::Provider::Service::Windows < Chef::Provider::Service include Chef::Mixin::ShellOut RUNNING = 'running' STOPPED = 'stopped' AUTO_START = 'auto start' DISABLED = 'disabled' def whyrun_supported? false end def load_current_resource @current_resource = Chef::Resource::Service.new(@new_resource.name) @current_resource.service_name(@new_resource.service_name) @current_resource.running(current_state == RUNNING) Chef::Log.debug "#{@new_resource} running: #{@current_resource.running}" @current_resource.enabled(start_type == AUTO_START) Chef::Log.debug "#{@new_resource} enabled: #{@current_resource.enabled}" @current_resource end def start_service if Win32::Service.exists?(@new_resource.service_name) if current_state == RUNNING Chef::Log.debug "#{@new_resource} already started - nothing to do" else if @new_resource.start_command Chef::Log.debug "#{@new_resource} starting service using the given start_command" shell_out!(@new_resource.start_command) else spawn_command_thread do Win32::Service.start(@new_resource.service_name) wait_for_state(RUNNING) end end @new_resource.updated_by_last_action(true) end else Chef::Log.debug "#{@new_resource} does not exist - nothing to do" end end def stop_service if Win32::Service.exists?(@new_resource.service_name) if current_state == RUNNING if @new_resource.stop_command Chef::Log.debug "#{@new_resource} stopping service using the given stop_command" shell_out!(@new_resource.stop_command) else spawn_command_thread do Win32::Service.stop(@new_resource.service_name) wait_for_state(STOPPED) end end @new_resource.updated_by_last_action(true) else Chef::Log.debug "#{@new_resource} already stopped - nothing to do" end else Chef::Log.debug "#{@new_resource} does not exist - nothing to do" end end def restart_service if Win32::Service.exists?(@new_resource.service_name) if @new_resource.restart_command Chef::Log.debug "#{@new_resource} restarting service using the given restart_command" shell_out!(@new_resource.restart_command) else stop_service start_service end @new_resource.updated_by_last_action(true) else Chef::Log.debug "#{@new_resource} does not exist - nothing to do" end end def enable_service if Win32::Service.exists?(@new_resource.service_name) if start_type == AUTO_START Chef::Log.debug "#{@new_resource} already enabled - nothing to do" else Win32::Service.configure( :service_name => @new_resource.service_name, :start_type => Win32::Service::AUTO_START ) @new_resource.updated_by_last_action(true) end else Chef::Log.debug "#{@new_resource} does not exist - nothing to do" end end def disable_service if Win32::Service.exists?(@new_resource.service_name) if start_type == AUTO_START Win32::Service.configure( :service_name => @new_resource.service_name, :start_type => Win32::Service::DISABLED ) @new_resource.updated_by_last_action(true) else Chef::Log.debug "#{@new_resource} already disabled - nothing to do" end else Chef::Log.debug "#{@new_resource} does not exist - nothing to do" end end private def current_state Win32::Service.status(@new_resource.service_name).current_state end def start_type Win32::Service.config_info(@new_resource.service_name).start_type end # Helper method that waits for a status to change its state since state # changes aren't usually instantaneous. def wait_for_state(desired_state) sleep 1 until current_state == desired_state end # There ain't no party like a thread party... def spawn_command_thread worker = Thread.new do yield end Timeout.timeout(60) do worker.join end end end chef-11.8.2/lib/chef/provider/service/arch.rb0000644000004100000410000000675012254362222020757 0ustar www-datawww-data# # Author:: Jan Zimmek () # Copyright:: Copyright (c) 2010 Jan Zimmek # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/service/init' require 'chef/mixin/command' class Chef::Provider::Service::Arch < Chef::Provider::Service::Init def initialize(new_resource, run_context) super @init_command = "/etc/rc.d/#{@new_resource.service_name}" end def load_current_resource raise Chef::Exceptions::Service, "Could not find /etc/rc.conf" unless ::File.exists?("/etc/rc.conf") raise Chef::Exceptions::Service, "No DAEMONS found in /etc/rc.conf" unless ::File.read("/etc/rc.conf").match(/DAEMONS=\((.*)\)/m) super @current_resource.enabled(daemons.include?(@current_resource.service_name)) @current_resource end # Get list of all daemons from the file '/etc/rc.conf'. # Mutiple lines and background form are supported. Example: # DAEMONS=(\ # foobar \ # @example \ # !net \ # ) def daemons entries = [] if ::File.read("/etc/rc.conf").match(/DAEMONS=\((.*)\)/m) entries += $1.gsub(/\\?[\r\n]/, ' ').gsub(/# *[^ ]+/,' ').split(' ') if $1.length > 0 end yield(entries) if block_given? entries end # FIXME: Multiple entries of DAEMONS will cause very bad results :) def update_daemons(entries) content = ::File.read("/etc/rc.conf").gsub(/DAEMONS=\((.*)\)/m, "DAEMONS=(#{entries.join(' ')})") ::File.open("/etc/rc.conf", "w") do |f| f.write(content) end end def enable_service() new_daemons = [] entries = daemons if entries.include?(new_resource.service_name) or entries.include?("@#{new_resource.service_name}") # exists and already enabled (or already enabled as a background service) # new_daemons += entries else if entries.include?("!#{new_resource.service_name}") # exists but disabled entries.each do |daemon| if daemon == "!#{new_resource.service_name}" new_daemons << new_resource.service_name else new_daemons << daemon end end else # does not exist new_daemons += entries new_daemons << new_resource.service_name end update_daemons(new_daemons) end end def disable_service() new_daemons = [] entries = daemons if entries.include?("!#{new_resource.service_name}") # exists and disabled # new_daemons += entries else if entries.include?(new_resource.service_name) or entries.include?("@#{new_resource.service_name}") # exists but enabled (or enabled as a back-ground service) # FIXME: Does arch support !@foobar ? entries.each do |daemon| if [new_resource.service_name, "@#{new_resource.service_name}"].include?(daemon) new_daemons << "!#{new_resource.service_name}" else new_daemons << daemon end end end update_daemons(new_daemons) end end end chef-11.8.2/lib/chef/provider/remote_file.rb0000644000004100000410000000256112254362222020670 0ustar www-datawww-data# # Author:: Jesse Campbell () # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/file' require 'chef/deprecation/provider/remote_file' require 'chef/deprecation/warnings' class Chef class Provider class RemoteFile < Chef::Provider::File extend Chef::Deprecation::Warnings include Chef::Deprecation::Provider::RemoteFile add_deprecation_warnings_for(Chef::Deprecation::Provider::RemoteFile.instance_methods) def initialize(new_resource, run_context) @content_class = Chef::Provider::RemoteFile::Content super end def load_current_resource @current_resource = Chef::Resource::RemoteFile.new(@new_resource.name) super end end end end chef-11.8.2/lib/chef/provider/env.rb0000644000004100000410000001124412254362222017164 0ustar www-datawww-data# # Author:: Doug MacEachern () # Copyright:: Copyright (c) 2010 VMware, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider' require 'chef/mixin/command' require 'chef/resource/env' class Chef class Provider class Env < Chef::Provider include Chef::Mixin::Command attr_accessor :key_exists def initialize(new_resource, run_context) super @key_exists = true end def load_current_resource @current_resource = Chef::Resource::Env.new(@new_resource.name) @current_resource.key_name(@new_resource.key_name) if env_key_exists(@new_resource.key_name) @current_resource.value(env_value(@new_resource.key_name)) else @key_exists = false Chef::Log.debug("#{@new_resource} key does not exist") end @current_resource end def env_value(key_name) raise Chef::Exceptions::Env, "#{self.to_s} provider does not implement env_value!" end def env_key_exists(key_name) env_value(key_name) ? true : false end # Check to see if value needs any changes # # ==== Returns # :: If a change is required # :: If a change is not required def compare_value if @new_resource.delim #e.g. check for existing value within PATH not @current_resource.value.split(@new_resource.delim).any? do |val| val == @new_resource.value end else @new_resource.value != @current_resource.value end end def action_create if @key_exists if compare_value modify_env Chef::Log.info("#{@new_resource} altered") @new_resource.updated_by_last_action(true) end else create_env Chef::Log.info("#{@new_resource} created") @new_resource.updated_by_last_action(true) end end #e.g. delete a PATH element # # ==== Returns # :: If we handled the element case and caller should not delete the key # :: Caller should delete the key, either no :delim was specific or value was empty # after we removed the element. def delete_element return false unless @new_resource.delim #no delim: delete the key if compare_value Chef::Log.debug("#{@new_resource} element '#{@new_resource.value}' does not exist") return true #do not delete the key else new_value = @current_resource.value.split(@new_resource.delim).select { |item| item != @new_resource.value }.join(@new_resource.delim) if new_value.empty? return false #nothing left here, delete the key else old_value = @new_resource.value(new_value) create_env Chef::Log.debug("#{@new_resource} deleted #{old_value} element") @new_resource.updated_by_last_action(true) return true #we removed the element and updated; do not delete the key end end end def action_delete if @key_exists && !delete_element delete_env Chef::Log.info("#{@new_resource} deleted") @new_resource.updated_by_last_action(true) end end def action_modify if @key_exists if compare_value modify_env Chef::Log.info("#{@new_resource} modified") @new_resource.updated_by_last_action(true) end else raise Chef::Exceptions::Env, "Cannot modify #{@new_resource} - key does not exist!" end end def create_env raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :#{@new_resource.action}" end def delete_env raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :delete" end def modify_env if @new_resource.delim #e.g. add to PATH @new_resource.value << @new_resource.delim << @current_resource.value end create_env end end end end chef-11.8.2/lib/chef/provider/template_finder.rb0000644000004100000410000000317112254362222021536 0ustar www-datawww-data#-- # Author:: Andrea Campi () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Provider class TemplateFinder def initialize(run_context, cookbook_name, node) @run_context = run_context @cookbook_name = cookbook_name @node = node end def find(template_name, options = {}) template_name = template_source_name(template_name, options) if options[:local] return template_name end cookbook_name = find_cookbook_name(options) cookbook = @run_context.cookbook_collection[cookbook_name] cookbook.preferred_filename_on_disk_location(@node, :templates, template_name) end protected def template_source_name(name, options) if options[:source] options[:source] else name end end def find_cookbook_name(options) if options[:cookbook] options[:cookbook] else @cookbook_name end end end end end chef-11.8.2/lib/chef/provider/deploy.rb0000644000004100000410000004204112254362222017667 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require "chef/mixin/command" require "chef/mixin/from_file" require "chef/monkey_patches/fileutils" require "chef/provider/git" require "chef/provider/subversion" require 'chef/dsl/recipe' class Chef class Provider class Deploy < Chef::Provider include Chef::DSL::Recipe include Chef::Mixin::FromFile include Chef::Mixin::Command attr_reader :scm_provider, :release_path, :previous_release_path def initialize(new_resource, run_context) super(new_resource, run_context) # will resolve to either git or svn based on resource attributes, # and will create a resource corresponding to that provider @scm_provider = new_resource.scm_provider.new(new_resource, run_context) # @configuration is not used by Deploy, it is only for backwards compat with # chef-deploy or capistrano hooks that might use it to get environment information @configuration = @new_resource.to_hash @configuration[:environment] = @configuration[:environment] && @configuration[:environment]["RAILS_ENV"] end def whyrun_supported? true end def load_current_resource @scm_provider.load_current_resource @release_path = @new_resource.deploy_to + "/releases/#{release_slug}" end def sudo(command,&block) execute(command, &block) end def run(command, &block) exec = execute(command, &block) exec.user(@new_resource.user) if @new_resource.user exec.group(@new_resource.group) if @new_resource.group exec.cwd(release_path) unless exec.cwd exec.environment(@new_resource.environment) unless exec.environment converge_by("execute #{command}") do exec end end def define_resource_requirements requirements.assert(:rollback) do |a| a.assertion { all_releases[-2] } a.failure_message(RuntimeError, "There is no release to rollback to!") #There is no reason to assume 2 deployments in a single chef run, hence fails in whyrun. end [ @new_resource.before_migrate, @new_resource.before_symlink, @new_resource.before_restart, @new_resource.after_restart ].each do |script| requirements.assert(:deploy, :force_deploy) do |a| callback_file = "#{release_path}/#{script}" a.assertion do if script && script.class == String ::File.exist?(callback_file) else true end end a.failure_message(RuntimeError, "Can't find your callback file #{callback_file}") a.whyrun("Would assume callback file #{callback_file} included in release") end end end def action_deploy save_release_state if deployed?(release_path ) if current_release?(release_path ) Chef::Log.debug("#{@new_resource} is the latest version") else rollback_to release_path end else with_rollback_on_error do deploy end end end def action_force_deploy if deployed?(release_path) converge_by("delete deployed app at #{release_path} prior to force-deploy") do Chef::Log.info("Already deployed app at #{release_path}, forcing.") FileUtils.rm_rf(release_path) Chef::Log.info("#{@new_resource} forcing deploy of already deployed app at #{release_path}") end end # Alternatives: # * Move release_path directory before deploy and move it back when error occurs # * Rollback to previous commit # * Do nothing - because deploy is force, it will be retried in short time # Because last is simpliest, keep it deploy end def action_rollback rollback_to all_releases[-2] end def rollback_to(target_release_path) @release_path = target_release_path rp_index = all_releases.index(release_path) releases_to_nuke = all_releases[(rp_index + 1)..-1] rollback releases_to_nuke.each do |i| converge_by("roll back by removing release #{i}") do Chef::Log.info "#{@new_resource} removing release: #{i}" FileUtils.rm_rf i end release_deleted(i) end end def deploy verify_directories_exist update_cached_repo # no converge-by - scm provider will dothis enforce_ownership copy_cached_repo install_gems enforce_ownership callback(:before_migrate, @new_resource.before_migrate) migrate callback(:before_symlink, @new_resource.before_symlink) symlink callback(:before_restart, @new_resource.before_restart) restart callback(:after_restart, @new_resource.after_restart) cleanup! Chef::Log.info "#{@new_resource} deployed to #{@new_resource.deploy_to}" end def rollback Chef::Log.info "#{@new_resource} rolling back to previous release #{release_path}" symlink Chef::Log.info "#{@new_resource} restarting with previous release" restart end def callback(what, callback_code=nil) @collection = Chef::ResourceCollection.new case callback_code when Proc Chef::Log.info "#{@new_resource} running callback #{what}" recipe_eval(&callback_code) when String run_callback_from_file("#{release_path}/#{callback_code}") when nil run_callback_from_file("#{release_path}/deploy/#{what}.rb") end end def migrate run_symlinks_before_migrate if @new_resource.migrate enforce_ownership environment = @new_resource.environment env_info = environment && environment.map do |key_and_val| "#{key_and_val.first}='#{key_and_val.last}'" end.join(" ") converge_by("execute migration command #{@new_resource.migration_command}") do Chef::Log.info "#{@new_resource} migrating #{@new_resource.user} with environment #{env_info}" run_command(run_options(:command => @new_resource.migration_command, :cwd=>release_path, :log_level => :info)) end end end def symlink purge_tempfiles_from_current_release link_tempfiles_to_current_release link_current_release_to_production Chef::Log.info "#{@new_resource} updated symlinks" end def restart if restart_cmd = @new_resource.restart_command if restart_cmd.kind_of?(Proc) Chef::Log.info("#{@new_resource} restarting app with embedded recipe") recipe_eval(&restart_cmd) else converge_by("restart app using command #{@new_resource.restart_command}") do Chef::Log.info("#{@new_resource} restarting app") run_command(run_options(:command => @new_resource.restart_command, :cwd => @new_resource.current_path)) end end end end def cleanup! converge_by("update release history data") do release_created(release_path) end chop = -1 - @new_resource.keep_releases all_releases[0..chop].each do |old_release| converge_by("remove old release #{old_release}") do Chef::Log.info "#{@new_resource} removing old release #{old_release}" FileUtils.rm_rf(old_release) end release_deleted(old_release) end end def all_releases Dir.glob(@new_resource.deploy_to + "/releases/*").sort end def update_cached_repo if @new_resource.svn_force_export # TODO assertion, non-recoverable - @scm_provider must be svn if force_export? svn_force_export else run_scm_sync end end def run_scm_sync @scm_provider.run_action(:sync) end def svn_force_export Chef::Log.info "#{@new_resource} exporting source repository" @scm_provider.run_action(:force_export) end def copy_cached_repo target_dir_path = @new_resource.deploy_to + "/releases" converge_by("deploy from repo to #{@target_dir_path} ") do FileUtils.rm_rf(release_path) if ::File.exist?(release_path) FileUtils.mkdir_p(target_dir_path) FileUtils.cp_r(::File.join(@new_resource.destination, "."), release_path, :preserve => true) Chef::Log.info "#{@new_resource} copied the cached checkout to #{release_path}" end end def enforce_ownership converge_by("force ownership of #{@new_resource.deploy_to} to #{@new_resource.group}:#{@new_resource.user}") do FileUtils.chown_R(@new_resource.user, @new_resource.group, @new_resource.deploy_to) Chef::Log.info("#{@new_resource} set user to #{@new_resource.user}") if @new_resource.user Chef::Log.info("#{@new_resource} set group to #{@new_resource.group}") if @new_resource.group end end def verify_directories_exist create_dir_unless_exists(@new_resource.deploy_to) create_dir_unless_exists(@new_resource.shared_path) end def link_current_release_to_production converge_by(["remove existing link at #{@new_resource.current_path}", "link release #{release_path} into production at #{@new_resource.current_path}"]) do FileUtils.rm_f(@new_resource.current_path) begin FileUtils.ln_sf(release_path, @new_resource.current_path) rescue => e raise Chef::Exceptions::FileNotFound.new("Cannot symlink current release to production: #{e.message}") end Chef::Log.info "#{@new_resource} linked release #{release_path} into production at #{@new_resource.current_path}" end enforce_ownership end def run_symlinks_before_migrate links_info = @new_resource.symlink_before_migrate.map { |src, dst| "#{src} => #{dst}" }.join(", ") converge_by("make pre-migration symlinks: #{links_info}") do @new_resource.symlink_before_migrate.each do |src, dest| begin FileUtils.ln_sf(@new_resource.shared_path + "/#{src}", release_path + "/#{dest}") rescue => e raise Chef::Exceptions::FileNotFound.new("Cannot symlink #{@new_resource.shared_path}/#{src} to #{release_path}/#{dest} before migrate: #{e.message}") end end Chef::Log.info "#{@new_resource} made pre-migration symlinks" end end def link_tempfiles_to_current_release dirs_info = @new_resource.create_dirs_before_symlink.join(",") @new_resource.create_dirs_before_symlink.each do |dir| create_dir_unless_exists(release_path + "/#{dir}") end Chef::Log.info("#{@new_resource} created directories before symlinking: #{dirs_info}") links_info = @new_resource.symlinks.map { |src, dst| "#{src} => #{dst}" }.join(", ") converge_by("link shared paths into current release: #{links_info}") do @new_resource.symlinks.each do |src, dest| begin FileUtils.ln_sf(::File.join(@new_resource.shared_path, src), ::File.join(release_path, dest)) rescue => e raise Chef::Exceptions::FileNotFound.new("Cannot symlink shared data #{::File.join(@new_resource.shared_path, src)} to #{::File.join(release_path, dest)}: #{e.message}") end end Chef::Log.info("#{@new_resource} linked shared paths into current release: #{links_info}") end run_symlinks_before_migrate enforce_ownership end def create_dirs_before_symlink end def purge_tempfiles_from_current_release log_info = @new_resource.purge_before_symlink.join(", ") converge_by("purge directories in checkout #{log_info}") do @new_resource.purge_before_symlink.each { |dir| FileUtils.rm_rf(release_path + "/#{dir}") } Chef::Log.info("#{@new_resource} purged directories in checkout #{log_info}") end end protected # Internal callback, called after copy_cached_repo. # Override if you need to keep state externally. # Note that YOU are responsible for implementing whyrun-friendly behavior # in any actions you take in this callback. def release_created(release_path) end # Note that YOU are responsible for using appropriate whyrun nomenclature # Override if you need to keep state externally. # Note that YOU are responsible for implementing whyrun-friendly behavior # in any actions you take in this callback. def release_deleted(release_path) end def release_slug raise Chef::Exceptions::Override, "You must override release_slug in #{self.to_s}" end def install_gems gem_resource_collection_runner.converge end def gem_resource_collection_runner gems_collection = Chef::ResourceCollection.new gem_packages.each { |rbgem| gems_collection << rbgem } gems_run_context = run_context.dup gems_run_context.resource_collection = gems_collection Chef::Runner.new(gems_run_context) end def gem_packages return [] unless ::File.exist?("#{release_path}/gems.yml") gems = YAML.load(IO.read("#{release_path}/gems.yml")) gems.map do |g| r = Chef::Resource::GemPackage.new(g[:name], run_context) r.version g[:version] r.action :install r.source "http://gems.github.com" r end end def run_options(run_opts={}) run_opts[:user] = @new_resource.user if @new_resource.user run_opts[:group] = @new_resource.group if @new_resource.group run_opts[:environment] = @new_resource.environment if @new_resource.environment run_opts[:log_tag] = @new_resource.to_s run_opts[:log_level] ||= :debug if run_opts[:log_level] == :info if STDOUT.tty? && !Chef::Config[:daemon] && Chef::Log.info? run_opts[:live_stream] = STDOUT end end run_opts end def run_callback_from_file(callback_file) Chef::Log.info "#{@new_resource} queueing checkdeploy hook #{callback_file}" recipe_eval do Dir.chdir(release_path) do from_file(callback_file) if ::File.exist?(callback_file) end end end def create_dir_unless_exists(dir) if ::File.directory?(dir) Chef::Log.debug "#{@new_resource} not creating #{dir} because it already exists" return false end converge_by("create new directory #{dir}") do begin FileUtils.mkdir_p(dir) Chef::Log.debug "#{@new_resource} created directory #{dir}" if @new_resource.user FileUtils.chown(@new_resource.user, nil, dir) Chef::Log.debug("#{@new_resource} set user to #{@new_resource.user} for #{dir}") end if @new_resource.group FileUtils.chown(nil, @new_resource.group, dir) Chef::Log.debug("#{@new_resource} set group to #{@new_resource.group} for #{dir}") end rescue => e raise Chef::Exceptions::FileNotFound.new("Cannot create directory #{dir}: #{e.message}") end end end def with_rollback_on_error yield rescue ::Exception => e if @new_resource.rollback_on_error Chef::Log.warn "Error on deploying #{release_path}: #{e.message}" failed_release = release_path if previous_release_path @release_path = previous_release_path rollback end converge_by("remove failed deploy #{failed_release}") do Chef::Log.info "Removing failed deploy #{failed_release}" FileUtils.rm_rf failed_release end release_deleted(failed_release) end raise end def save_release_state if ::File.exists?(@new_resource.current_path) release = ::File.readlink(@new_resource.current_path) @previous_release_path = release if ::File.exists?(release) end end def deployed?(release) all_releases.include?(release) end def current_release?(release) @previous_release_path == release end end end end chef-11.8.2/lib/chef/provider/cron/0000755000004100000410000000000012254362222017006 5ustar www-datawww-datachef-11.8.2/lib/chef/provider/cron/solaris.rb0000644000004100000410000000160712254362222021013 0ustar www-datawww-data# # Author:: Kaustubh Deorukhkar () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require "chef/provider/cron/unix" # Just to create an alias so 'Chef::Provider::Cron::Solaris' is exposed and accessible to existing consumers of class. Chef::Provider::Cron::Solaris = Chef::Provider::Cron::Unix chef-11.8.2/lib/chef/provider/cron/aix.rb0000644000004100000410000000320212254362222020111 0ustar www-datawww-data# # Author:: Kaustubh Deorukhkar () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require "chef/provider/cron/unix" class Chef class Provider class Cron class Aix < Chef::Provider::Cron::Unix private # For AIX we ignore env vars/[ :mailto, :path, :shell, :home ] def get_crontab_entry if env_vars_are_set? raise Chef::Exceptions::Cron, "Aix cron entry does not support environment variables. Please set them in script and use script in cron." end newcron = "" newcron << "# Chef Name: #{new_resource.name}\n" newcron << "#{@new_resource.minute} #{@new_resource.hour} #{@new_resource.day} #{@new_resource.month} #{@new_resource.weekday}" newcron << " #{@new_resource.command}\n" newcron end def env_vars_are_set? @new_resource.environment.length > 0 || !@new_resource.mailto.nil? || !@new_resource.path.nil? || !@new_resource.shell.nil? || !@new_resource.home.nil? end end end end end chef-11.8.2/lib/chef/provider/cron/unix.rb0000644000004100000410000000512212254362222020316 0ustar www-datawww-data# # Author:: Bryan McLellan (btm@loftninjas.org) # Author:: Toomas Pelberg (toomasp@gmx.net) # Copyright:: Copyright (c) 2009 Bryan McLellan # Copyright:: Copyright (c) 2010 Toomas Pelberg # License:: Apache License, Version 2.0 # # 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. # require 'chef/log' require 'chef/provider' class Chef class Provider class Cron class Unix < Chef::Provider::Cron private def read_crontab crontab = nil status = popen4("crontab -l #{@new_resource.user}") do |pid, stdin, stdout, stderr| crontab = stdout.read end if status.exitstatus > 1 raise Chef::Exceptions::Cron, "Error determining state of #{@new_resource.name}, exit: #{status.exitstatus}" end crontab end def write_crontab(crontab) tempcron = Tempfile.new("chef-cron") tempcron << crontab tempcron.flush tempcron.chmod(0644) exit_status = 0 error_message = "" begin status, stdout, stderr = run_command_and_return_stdout_stderr(:command => "/usr/bin/crontab #{tempcron.path}",:user => @new_resource.user) exit_status = status.exitstatus # solaris9, 10 on some failures for example invalid 'mins' in crontab fails with exit code of zero :( if stderr && stderr.include?("errors detected in input, no crontab file generated") error_message = stderr exit_status = 1 end rescue Chef::Exceptions::Exec => e Chef::Log.debug(e.message) exit_status = 1 error_message = e.message rescue ArgumentError => e # usually raised on invalid user. Chef::Log.debug(e.message) exit_status = 1 error_message = e.message end tempcron.close! if exit_status > 0 raise Chef::Exceptions::Cron, "Error updating state of #{@new_resource.name}, exit: #{exit_status}, message: #{error_message}" end end end end end end chef-11.8.2/lib/chef/provider/resource_update.rb0000644000004100000410000000253112254362222021564 0ustar www-datawww-data class Chef class Provider # { # "run_id" : "1000", # "resource" : { # "type" : "file", # "name" : "/etc/passwd", # "start_time" : "2012-01-09T08:15:30-05:00", # "end_time" : "2012-01-09T08:15:30-05:00", # "status" : "modified", # "initial_state" : "exists", # "final_state" : "modified", # "before" : { # "group" : "root", # "owner" : "root", # "checksum" : "xyz" # }, # "after" : { # "group" : "root", # "owner" : "root", # "checksum" : "abc" # }, # "delta" : "escaped delta goes here" # }, # "event_data" : "" # } class ResourceUpdate attr_accessor :type attr_accessor :name attr_accessor :duration #ms attr_accessor :status attr_accessor :initial_state attr_accessor :final_state attr_accessor :initial_properties attr_accessor :final_properties attr_accessor :event_data # e.g., a diff. def initial_state_from_resource(resource) @initial_properties = resource.to_hash end def updated_state_from_resource(resource) @final_properties = resource.to_hash end end end end chef-11.8.2/lib/chef/provider/route.rb0000644000004100000410000001716112254362222017536 0ustar www-datawww-data# # Author:: Bryan McLellan (btm@loftninjas.org), Jesse Nelson (spheromak@gmail.com) # Copyright:: Copyright (c) 2009 Bryan McLellan # License:: Apache License, Version 2.0 # # 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. # require 'chef/log' require 'chef/mixin/command' require 'chef/provider' require 'ipaddr' class Chef::Provider::Route < Chef::Provider include Chef::Mixin::Command attr_accessor :is_running MASK = {'0.0.0.0' => '0', '128.0.0.0' => '1', '192.0.0.0' => '2', '224.0.0.0' => '3', '240.0.0.0' => '4', '248.0.0.0' => '5', '252.0.0.0' => '6', '254.0.0.0' => '7', '255.0.0.0' => '8', '255.128.0.0' => '9', '255.192.0.0' => '10', '255.224.0.0' => '11', '255.240.0.0' => '12', '255.248.0.0' => '13', '255.252.0.0' => '14', '255.254.0.0' => '15', '255.255.0.0' => '16', '255.255.128.0' => '17', '255.255.192.0' => '18', '255.255.224.0' => '19', '255.255.240.0' => '20', '255.255.248.0' => '21', '255.255.252.0' => '22', '255.255.254.0' => '23', '255.255.255.0' => '24', '255.255.255.128' => '25', '255.255.255.192' => '26', '255.255.255.224' => '27', '255.255.255.240' => '28', '255.255.255.248' => '29', '255.255.255.252' => '30', '255.255.255.254' => '31', '255.255.255.255' => '32' } def hex2ip(hex_data) # Cleanup hex data hex_ip = hex_data.to_s.downcase.gsub(/[^0-9a-f]/, '') # Check hex data format (IP is a 32bit integer, so should be 8 chars long) return nil if hex_ip.length != hex_data.length || hex_ip.length != 8 # Extract octets from hex data octets = hex_ip.scan(/../).reverse.collect { |octet| [octet].pack('H2').unpack("C").first } # Validate IP ip = octets.join('.') begin IPAddr.new(ip, Socket::AF_INET).to_s rescue ArgumentError Chef::Log.debug("Invalid IP address data: hex=#{hex_ip}, ip=#{ip}") return nil end end def whyrun_supported? true end def load_current_resource self.is_running = false # cidr or quad dot mask if @new_resource.netmask new_ip = IPAddr.new("#{@new_resource.target}/#{@new_resource.netmask}") else new_ip = IPAddr.new(@new_resource.target) end # For linux, we use /proc/net/route file to read proc table info if node[:os] == "linux" route_file = ::File.open("/proc/net/route", "r") # Read all routes while (line = route_file.gets) # Get all the fields for a route iface,destination,gateway,flags,refcnt,use,metric,mask,mtu,window,irtt = line.split # Convert hex-encoded values to quad-dotted notation (e.g. 0064A8C0 => 192.168.100.0) destination = hex2ip(destination) gateway = hex2ip(gateway) mask = hex2ip(mask) # Skip formatting lines (header, etc) next unless destination && gateway && mask Chef::Log.debug("#{@new_resource} system has route: dest=#{destination} mask=#{mask} gw=#{gateway}") # check if what were trying to configure is already there # use an ipaddr object with ip/mask this way we can have # a new resource be in cidr format (i don't feel like # expanding bitmask by hand. # running_ip = IPAddr.new("#{destination}/#{mask}") Chef::Log.debug("#{@new_resource} new ip: #{new_ip.inspect} running ip: #{running_ip.inspect}") self.is_running = true if running_ip == new_ip && gateway == @new_resource.gateway end route_file.close end end def action_add # check to see if load_current_resource found the route if is_running Chef::Log.debug("#{@new_resource} route already active - nothing to do") else command = generate_command(:add) converge_by ("run #{ command } to add route") do run_command( :command => command ) Chef::Log.info("#{@new_resource} added") end end #for now we always write the file (ugly but its what it is) generate_config end def action_delete if is_running command = generate_command(:delete) converge_by ("run #{ command } to delete route ") do run_command( :command => command ) Chef::Log.info("#{@new_resource} removed") end else Chef::Log.debug("#{@new_resource} route does not exist - nothing to do") end #for now we always write the file (ugly but its what it is) generate_config end def generate_config conf = Hash.new case node[:platform] when "centos", "redhat", "fedora" # walk the collection run_context.resource_collection.each do |resource| if resource.is_a? Chef::Resource::Route # default to eth0 if resource.device dev = resource.device else dev = "eth0" end conf[dev] = String.new if conf[dev].nil? case @action when :add conf[dev] << config_file_contents(:add, :target => resource.target, :netmask => resource.netmask, :gateway => resource.gateway) when :delete # need to do this for the case when the last route on an int # is removed conf[dev] << config_file_contents(:delete) end end end conf.each do |k, v| network_file_name = "/etc/sysconfig/network-scripts/route-#{k}" converge_by ("write route route.#{k}\n#{conf[k]} to #{ network_file_name }") do network_file = ::File.new(network_file_name, "w") network_file.puts(conf[k]) Chef::Log.debug("#{@new_resource} writing route.#{k}\n#{conf[k]}") network_file.close end end end end def generate_command(action) common_route_items = '' common_route_items << "/#{MASK[@new_resource.netmask.to_s]}" if @new_resource.netmask common_route_items << " via #{@new_resource.gateway} " if @new_resource.gateway case action when :add command = "ip route replace #{@new_resource.target}" command << common_route_items command << " dev #{@new_resource.device} " if @new_resource.device when :delete command = "ip route delete #{@new_resource.target}" command << common_route_items end return command end def config_file_contents(action, options={}) content = '' case action when :add content << "#{options[:target]}" content << "/#{options[:netmask]}" if options[:netmask] content << " via #{options[:gateway]}" if options[:gateway] content << "\n" end return content end end chef-11.8.2/lib/chef/provider/package/0000755000004100000410000000000012254362222017440 5ustar www-datawww-datachef-11.8.2/lib/chef/provider/package/ips.rb0000644000004100000410000000631312254362222020563 0ustar www-datawww-data# # Author:: Jason J. W. Williams () # Author:: Stephen Nelson-Smith () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'open3' require 'chef/provider/package' require 'chef/mixin/command' require 'chef/resource/package' require 'chef/mixin/shell_out' class Chef class Provider class Package class Ips < Chef::Provider::Package include Chef::Mixin::ShellOut attr_accessor :virtual def define_resource_requirements super requirements.assert(:all_actions) do |a| a.assertion { ! @candidate_version.nil? } a.failure_message Chef::Exceptions::Package, "Package #{@new_resource.package_name} not found" a.whyrun "Assuming package #{@new_resource.package_name} would have been made available." end end def load_current_resource @current_resource = Chef::Resource::Package.new(@new_resource.name) @current_resource.package_name(@new_resource.name) check_package_state(@new_resource.package_name) @current_resource end def check_package_state(package) Chef::Log.debug("Checking package status for #{package}") installed = false depends = false shell_out!("pkg info -r #{package}").stdout.each_line do |line| case line when /^\s+State: Installed/ installed = true when /^\s+Version: (.*)/ @candidate_version = $1.split[0] if installed @current_resource.version($1) else @current_resource.version(nil) end end end return installed end def install_package(name, version) package_name = "#{name}@#{version}" normal_command = "pkg#{expand_options(@new_resource.options)} install -q #{package_name}" if @new_resource.respond_to?(:accept_license) and @new_resource.accept_license command = normal_command.gsub('-q', '-q --accept') else command = normal_command end begin run_command_with_systems_locale(:command => command) rescue end end def upgrade_package(name, version) install_package(name, version) end def remove_package(name, version) package_name = "#{name}@#{version}" run_command_with_systems_locale( :command => "pkg#{expand_options(@new_resource.options)} uninstall -q #{package_name}" ) end end end end end chef-11.8.2/lib/chef/provider/package/zypper.rb0000644000004100000410000001032012254362222021312 0ustar www-datawww-data# -*- coding: utf-8 -*- # # Authors:: Adam Jacob () # Ionuț Arțăriși () # Copyright:: Copyright (c) 2008 Opscode, Inc. # Copyright (c) 2013 SUSE Linux GmbH # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/package' require 'chef/mixin/command' require 'chef/resource/package' require 'chef/mixin/shell_out' require 'singleton' class Chef class Provider class Package class Zypper < Chef::Provider::Package include Chef::Mixin::ShellOut def load_current_resource @current_resource = Chef::Resource::Package.new(@new_resource.name) @current_resource.package_name(@new_resource.package_name) is_installed=false is_out_of_date=false version='' oud_version='' Chef::Log.debug("#{@new_resource} checking zypper") status = popen4("zypper --non-interactive info #{@new_resource.package_name}") do |pid, stdin, stdout, stderr| stdout.each do |line| case line when /^Version: (.+)$/ version = $1 Chef::Log.debug("#{@new_resource} version #{$1}") when /^Installed: Yes$/ is_installed=true Chef::Log.debug("#{@new_resource} is installed") when /^Installed: No$/ is_installed=false Chef::Log.debug("#{@new_resource} is not installed") when /^Status: out-of-date \(version (.+) installed\)$/ is_out_of_date=true oud_version=$1 Chef::Log.debug("#{@new_resource} out of date version #{$1}") end end end if is_installed==false @candidate_version=version @current_resource.version(nil) end if is_installed==true if is_out_of_date==true @current_resource.version(oud_version) @candidate_version=version else @current_resource.version(version) @candidate_version=version end end unless status.exitstatus == 0 raise Chef::Exceptions::Package, "zypper failed - #{status.inspect}!" end @current_resource end def zypper_version() `zypper -V 2>&1`.scan(/\d+/).join(".").to_f end def install_package(name, version) zypper_package("install --auto-agree-with-licenses", name, version) end def upgrade_package(name, version) install_package(name, version) end def remove_package(name, version) zypper_package("remove", name, version) end def purge_package(name, version) zypper_package("remove --clean-deps", name, version) end private def zypper_package(command, pkgname, version) version = "=#{version}" unless version.empty? if zypper_version < 1.0 shell_out!("zypper#{gpg_checks} #{command} -y #{pkgname}") else shell_out!("zypper --non-interactive#{gpg_checks} "+ "#{command} #{pkgname}#{version}") end end def gpg_checks() case Chef::Config[:zypper_check_gpg] when true "" when false " --no-gpg-checks" when nil Chef::Log.warn("Chef::Config[:zypper_check_gpg] was not set. " + "All packages will be installed without gpg signature checks. " + "This is a security hazard.") " --no-gpg-checks" end end end end end end chef-11.8.2/lib/chef/provider/package/apt.rb0000644000004100000410000001276412254362222020563 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/package' require 'chef/mixin/command' require 'chef/resource/package' require 'chef/mixin/shell_out' class Chef class Provider class Package class Apt < Chef::Provider::Package include Chef::Mixin::ShellOut attr_accessor :is_virtual_package def load_current_resource @current_resource = Chef::Resource::Package.new(@new_resource.name) @current_resource.package_name(@new_resource.package_name) check_package_state(@new_resource.package_name) @current_resource end def default_release_options # Use apt::Default-Release option only if provider was explicitly defined "-o APT::Default-Release=#{@new_resource.default_release}" if @new_resource.provider && @new_resource.default_release end def check_package_state(package) Chef::Log.debug("#{@new_resource} checking package status for #{package}") installed = false shell_out!("apt-cache#{expand_options(default_release_options)} policy #{package}").stdout.each_line do |line| case line when /^\s{2}Installed: (.+)$/ installed_version = $1 if installed_version == '(none)' Chef::Log.debug("#{@new_resource} current version is nil") @current_resource.version(nil) else Chef::Log.debug("#{@new_resource} current version is #{installed_version}") @current_resource.version(installed_version) installed = true end when /^\s{2}Candidate: (.+)$/ candidate_version = $1 if candidate_version == '(none)' # This may not be an appropriate assumption, but it shouldn't break anything that already worked -- btm @is_virtual_package = true showpkg = shell_out!("apt-cache showpkg #{package}").stdout providers = Hash.new # Returns all lines after 'Reverse Provides:' showpkg.rpartition(/Reverse Provides:\s*#{$/}/)[2].each_line do |line| provider, version = line.split providers[provider] = version end # Check if the package providing this virtual package is installed num_providers = providers.length raise Chef::Exceptions::Package, "#{@new_resource.package_name} has no candidate in the apt-cache" if num_providers == 0 # apt will only install a virtual package if there is a single providing package raise Chef::Exceptions::Package, "#{@new_resource.package_name} is a virtual package provided by #{num_providers} packages, you must explicitly select one to install" if num_providers > 1 # Check if the package providing this virtual package is installed Chef::Log.info("#{@new_resource} is a virtual package, actually acting on package[#{providers.keys.first}]") installed = check_package_state(providers.keys.first) else Chef::Log.debug("#{@new_resource} candidate version is #{$1}") @candidate_version = $1 end end end return installed end def install_package(name, version) package_name = "#{name}=#{version}" package_name = name if @is_virtual_package run_noninteractive("apt-get -q -y#{expand_options(default_release_options)}#{expand_options(@new_resource.options)} install #{package_name}") end def upgrade_package(name, version) install_package(name, version) end def remove_package(name, version) package_name = "#{name}" run_noninteractive("apt-get -q -y#{expand_options(@new_resource.options)} remove #{package_name}") end def purge_package(name, version) run_noninteractive("apt-get -q -y#{expand_options(@new_resource.options)} purge #{@new_resource.package_name}") end def preseed_package(preseed_file) Chef::Log.info("#{@new_resource} pre-seeding package installation instructions") run_noninteractive("debconf-set-selections #{preseed_file}") end def reconfig_package(name, version) Chef::Log.info("#{@new_resource} reconfiguring") run_noninteractive("dpkg-reconfigure #{name}") end private # Runs command via shell_out with magic environment to disable # interactive prompts. Command is run with default localization rather # than forcing locale to "C", so command output may not be stable. def run_noninteractive(command) shell_out!(command, :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }) end end end end end chef-11.8.2/lib/chef/provider/package/smartos.rb0000644000004100000410000000645212254362222021464 0ustar www-datawww-data# # Authors:: Trevor O (trevoro@joyent.com) # Bryan McLellan (btm@loftninjas.org) # Matthew Landauer (matthew@openaustralia.org) # Ben Rockwood (benr@joyent.com) # Copyright:: Copyright (c) 2009 Bryan McLellan, Matthew Landauer # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/package' require 'chef/mixin/shell_out' require 'chef/resource/package' require 'chef/mixin/get_source_from_package' class Chef class Provider class Package class SmartOS < Chef::Provider::Package include Chef::Mixin::ShellOut attr_accessor :is_virtual_package def load_current_resource Chef::Log.debug("#{@new_resource} loading current resource") @current_resource = Chef::Resource::Package.new(@new_resource.name) @current_resource.package_name(@new_resource.package_name) @current_resource.version(nil) check_package_state(@new_resource.package_name) @current_resource # modified by check_package_state end def check_package_state(name) Chef::Log.debug("#{@new_resource} checking package #{name}") version = nil info = shell_out!("/opt/local/sbin/pkg_info -E \"#{name}*\"", :env => nil, :returns => [0,1]) if info.stdout version = info.stdout[/^#{@new_resource.package_name}-(.+)/, 1] end if !version @current_resource.version(nil) else @current_resource.version(version) end end def candidate_version return @candidate_version if @candidate_version name = nil version = nil pkg = shell_out!("/opt/local/bin/pkgin se #{new_resource.package_name}", :env => nil, :returns => [0,1]) pkg.stdout.each_line do |line| case line when /^#{new_resource.package_name}/ name, version = line.split[0].split(/-([^-]+)$/) end end @candidate_version = version version end def install_package(name, version) Chef::Log.debug("#{@new_resource} installing package #{name} version #{version}") package = "#{name}-#{version}" out = shell_out!("/opt/local/bin/pkgin -y install #{package}", :env => nil) end def upgrade_package(name, version) Chef::Log.debug("#{@new_resource} upgrading package #{name} version #{version}") install_package(name, version) end def remove_package(name, version) Chef::Log.debug("#{@new_resource} removing package #{name} version #{version}") package = "#{name}" out = shell_out!("/opt/local/bin/pkgin -y remove #{package}", :env => nil) end end end end end chef-11.8.2/lib/chef/provider/package/freebsd.rb0000644000004100000410000001317112254362222021402 0ustar www-datawww-data# # Authors:: Bryan McLellan (btm@loftninjas.org) # Matthew Landauer (matthew@openaustralia.org) # Copyright:: Copyright (c) 2009 Bryan McLellan, Matthew Landauer # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/package' require 'chef/mixin/shell_out' require 'chef/resource/package' require 'chef/mixin/get_source_from_package' class Chef class Provider class Package class Freebsd < Chef::Provider::Package include Chef::Mixin::ShellOut include Chef::Mixin::GetSourceFromPackage def initialize(*args) super @current_resource = Chef::Resource::Package.new(@new_resource.name) end def current_installed_version pkg_info = shell_out!("pkg_info -E \"#{package_name}*\"", :env => nil, :returns => [0,1]) pkg_info.stdout[/^#{Regexp.escape(package_name)}-(.+)/, 1] end def port_path case @new_resource.package_name # When the package name starts with a '/' treat it as the full path to the ports directory when /^\// @new_resource.package_name # Otherwise if the package name contains a '/' not at the start (like 'www/wordpress') treat as a relative # path from /usr/ports when /\// "/usr/ports/#{@new_resource.package_name}" # Otherwise look up the path to the ports directory using 'whereis' else whereis = shell_out!("whereis -s #{@new_resource.package_name}", :env => nil) unless path = whereis.stdout[/^#{Regexp.escape(@new_resource.package_name)}:\s+(.+)$/, 1] raise Chef::Exceptions::Package, "Could not find port with the name #{@new_resource.package_name}" end path end end def ports_makefile_variable_value(variable) make_v = shell_out!("make -V #{variable}", :cwd => port_path, :env => nil, :returns => [0,1]) make_v.stdout.strip.split($\).first # $\ is the line separator, i.e., newline end def ports_candidate_version ports_makefile_variable_value("PORTVERSION") end def file_candidate_version_path Dir["#{@new_resource.source}/#{@current_resource.package_name}*"][-1].to_s end def file_candidate_version file_candidate_version_path.split(/-/).last.split(/.tbz/).first end def load_current_resource @current_resource.package_name(@new_resource.package_name) @current_resource.version(current_installed_version) Chef::Log.debug("#{@new_resource} current version is #{@current_resource.version}") if @current_resource.version case @new_resource.source when /^http/, /^ftp/ @candidate_version = "0.0.0" when /^\// @candidate_version = file_candidate_version else @candidate_version = ports_candidate_version end Chef::Log.debug("#{@new_resource} ports candidate version is #{@candidate_version}") if @candidate_version @current_resource end def latest_link_name ports_makefile_variable_value("LATEST_LINK") end # The name of the package (without the version number) as understood by pkg_add and pkg_info def package_name if ::File.exist?("/usr/ports/Makefile") if ports_makefile_variable_value("PKGNAME") =~ /^(.+)-[^-]+$/ $1 else raise Chef::Exceptions::Package, "Unexpected form for PKGNAME variable in #{port_path}/Makefile" end else @new_resource.package_name end end def install_package(name, version) unless @current_resource.version case @new_resource.source when /^ports$/ shell_out!("make -DBATCH install", :timeout => 1200, :env => nil, :cwd => port_path).status when /^http/, /^ftp/ if @new_resource.source =~ /\/$/ shell_out!("pkg_add -r #{package_name}", :env => { "PACKAGESITE" => @new_resource.source, 'LC_ALL' => nil }).status else shell_out!("pkg_add -r #{package_name}", :env => { "PACKAGEROOT" => @new_resource.source, 'LC_ALL' => nil }).status end Chef::Log.debug("#{@new_resource} installed from: #{@new_resource.source}") when /^\// shell_out!("pkg_add #{file_candidate_version_path}", :env => { "PKG_PATH" => @new_resource.source , 'LC_ALL'=>nil}).status Chef::Log.debug("#{@new_resource} installed from: #{@new_resource.source}") else shell_out!("pkg_add -r #{latest_link_name}", :env => nil).status end end end def remove_package(name, version) # a version is mandatory if version shell_out!("pkg_delete #{package_name}-#{version}", :env => nil).status else shell_out!("pkg_delete #{package_name}-#{@current_resource.version}", :env => nil).status end end end end end end chef-11.8.2/lib/chef/provider/package/yum.rb0000644000004100000410000012037212254362222020604 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/config' require 'chef/provider/package' require 'chef/mixin/command' require 'chef/mixin/shell_out' require 'chef/resource/package' require 'singleton' require 'chef/mixin/get_source_from_package' class Chef class Provider class Package class Yum < Chef::Provider::Package class RPMUtils class << self # RPM::Version version_parse equivalent def version_parse(evr) return if evr.nil? epoch = nil # assume this is a version version = evr release = nil lead = 0 tail = evr.size if evr =~ %r{^([\d]+):} epoch = $1.to_i lead = $1.length + 1 elsif evr[0].ord == ":".ord epoch = 0 lead = 1 end if evr =~ %r{:?.*-(.*)$} release = $1 tail = evr.length - release.length - lead - 1 if release.empty? release = nil end end version = evr[lead,tail] if version.empty? version = nil end [ epoch, version, release ] end # verify def isalnum(x) isalpha(x) or isdigit(x) end def isalpha(x) v = x.ord (v >= 65 and v <= 90) or (v >= 97 and v <= 122) end def isdigit(x) v = x.ord v >= 48 and v <= 57 end # based on the reference spec in lib/rpmvercmp.c in rpm 4.9.0 def rpmvercmp(x, y) # easy! :) return 0 if x == y if x.nil? x = "" end if y.nil? y = "" end # not so easy :( # # takes 2 strings like # # x = "1.20.b18.el5" # y = "1.20.b17.el5" # # breaks into purely alpha and numeric segments and compares them using # some rules # # * 10 > 1 # * 1 > a # * z > a # * Z > A # * z > Z # * leading zeros are ignored # * separators (periods, commas) are ignored # * "1.20.b18.el5.extrastuff" > "1.20.b18.el5" x_pos = 0 # overall string element reference position x_pos_max = x.length - 1 # number of elements in string, starting from 0 x_seg_pos = 0 # segment string element reference position x_comp = nil # segment to compare y_pos = 0 y_seg_pos = 0 y_pos_max = y.length - 1 y_comp = nil while (x_pos <= x_pos_max and y_pos <= y_pos_max) # first we skip over anything non alphanumeric while (x_pos <= x_pos_max) and (isalnum(x[x_pos]) == false) x_pos += 1 # +1 over pos_max if end of string end while (y_pos <= y_pos_max) and (isalnum(y[y_pos]) == false) y_pos += 1 end # if we hit the end of either we are done matching segments if (x_pos == x_pos_max + 1) or (y_pos == y_pos_max + 1) break end # we are now at the start of a alpha or numeric segment x_seg_pos = x_pos y_seg_pos = y_pos # grab segment so we can compare them if isdigit(x[x_seg_pos].ord) x_seg_is_num = true # already know it's a digit x_seg_pos += 1 # gather up our digits while (x_seg_pos <= x_pos_max) and isdigit(x[x_seg_pos]) x_seg_pos += 1 end # copy the segment but not the unmatched character that x_seg_pos will # refer to x_comp = x[x_pos,x_seg_pos - x_pos] while (y_seg_pos <= y_pos_max) and isdigit(y[y_seg_pos]) y_seg_pos += 1 end y_comp = y[y_pos,y_seg_pos - y_pos] else # we are comparing strings x_seg_is_num = false while (x_seg_pos <= x_pos_max) and isalpha(x[x_seg_pos]) x_seg_pos += 1 end x_comp = x[x_pos,x_seg_pos - x_pos] while (y_seg_pos <= y_pos_max) and isalpha(y[y_seg_pos]) y_seg_pos += 1 end y_comp = y[y_pos,y_seg_pos - y_pos] end # if y_seg_pos didn't advance in the above loop it means the segments are # different types if y_pos == y_seg_pos # numbers always win over letters return x_seg_is_num ? 1 : -1 end # move the ball forward before we mess with the segments x_pos += x_comp.length # +1 over pos_max if end of string y_pos += y_comp.length # we are comparing numbers - simply convert them if x_seg_is_num x_comp = x_comp.to_i y_comp = y_comp.to_i end # compares ints or strings # don't return if equal - try the next segment if x_comp > y_comp return 1 elsif x_comp < y_comp return -1 end # if we've reached here than the segments are the same - try again end # we must have reached the end of one or both of the strings and they # matched up until this point # segments matched completely but the segment separators were different - # rpm reference code treats these as equal. if (x_pos == x_pos_max + 1) and (y_pos == y_pos_max + 1) return 0 end # the most unprocessed characters left wins if (x_pos_max - x_pos) > (y_pos_max - y_pos) return 1 else return -1 end end end # self end # RPMUtils class RPMVersion include Comparable def initialize(*args) if args.size == 1 @e, @v, @r = RPMUtils.version_parse(args[0]) elsif args.size == 3 @e = args[0].to_i @v = args[1] @r = args[2] else raise ArgumentError, "Expecting either 'epoch-version-release' or 'epoch, " + "version, release'" end end attr_reader :e, :v, :r alias :epoch :e alias :version :v alias :release :r def self.parse(*args) self.new(*args) end def <=>(y) compare_versions(y) end def compare(y) compare_versions(y, false) end def partial_compare(y) compare_versions(y, true) end # RPM::Version rpm_version_to_s equivalent def to_s if @r.nil? @v else "#{@v}-#{@r}" end end def evr "#{@e}:#{@v}-#{@r}" end private # Rough RPM::Version rpm_version_cmp equivalent - except much slower :) # # partial lets epoch and version segment equality be good enough to return equal, eg: # # 2:1.2-1 == 2:1.2 # 2:1.2-1 == 2: # def compare_versions(y, partial=false) x = self # compare epoch if (x.e.nil? == false and x.e > 0) and y.e.nil? return 1 elsif x.e.nil? and (y.e.nil? == false and y.e > 0) return -1 elsif x.e.nil? == false and y.e.nil? == false if x.e < y.e return -1 elsif x.e > y.e return 1 end end # compare version if partial and (x.v.nil? or y.v.nil?) return 0 elsif x.v.nil? == false and y.v.nil? return 1 elsif x.v.nil? and y.v.nil? == false return -1 elsif x.v.nil? == false and y.v.nil? == false cmp = RPMUtils.rpmvercmp(x.v, y.v) return cmp if cmp != 0 end # compare release if partial and (x.r.nil? or y.r.nil?) return 0 elsif x.r.nil? == false and y.r.nil? return 1 elsif x.r.nil? and y.r.nil? == false return -1 elsif x.r.nil? == false and y.r.nil? == false cmp = RPMUtils.rpmvercmp(x.r, y.r) return cmp end return 0 end end class RPMPackage include Comparable def initialize(*args) if args.size == 4 @n = args[0] @version = RPMVersion.new(args[1]) @a = args[2] @provides = args[3] elsif args.size == 6 @n = args[0] e = args[1].to_i v = args[2] r = args[3] @version = RPMVersion.new(e,v,r) @a = args[4] @provides = args[5] else raise ArgumentError, "Expecting either 'name, epoch-version-release, arch, provides' " + "or 'name, epoch, version, release, arch, provides'" end # We always have one, ourselves! if @provides.empty? @provides = [ RPMProvide.new(@n, @version.evr, :==) ] end end attr_reader :n, :a, :version, :provides alias :name :n alias :arch :a def <=>(y) compare(y) end def compare(y) x = self # easy! :) return 0 if x.nevra == y.nevra # compare name if x.n.nil? == false and y.n.nil? return 1 elsif x.n.nil? and y.n.nil? == false return -1 elsif x.n.nil? == false and y.n.nil? == false if x.n < y.n return -1 elsif x.n > y.n return 1 end end # compare version if x.version > y.version return 1 elsif x.version < y.version return -1 end # compare arch if x.a.nil? == false and y.a.nil? return 1 elsif x.a.nil? and y.a.nil? == false return -1 elsif x.a.nil? == false and y.a.nil? == false if x.a < y.a return -1 elsif x.a > y.a return 1 end end return 0 end def to_s nevra end def nevra "#{@n}-#{@version.evr}.#{@a}" end end # Simple implementation from rpm and ruby-rpm reference code class RPMDependency def initialize(*args) if args.size == 3 @name = args[0] @version = RPMVersion.new(args[1]) # Our requirement to other dependencies @flag = args[2] || :== elsif args.size == 5 @name = args[0] e = args[1].to_i v = args[2] r = args[3] @version = RPMVersion.new(e,v,r) @flag = args[4] || :== else raise ArgumentError, "Expecting either 'name, epoch-version-release, flag' or " + "'name, epoch, version, release, flag'" end end attr_reader :name, :version, :flag # Parses 2 forms: # # "mtr >= 2:0.71-3.0" # "mta" def self.parse(string) if string =~ %r{^(\S+)\s+(>|>=|=|==|<=|<)\s+(\S+)$} name = $1 if $2 == "=" flag = :== else flag = :"#{$2}" end version = $3 return self.new(name, version, flag) else name = string return self.new(name, nil, nil) end end # Test if another RPMDependency satisfies our requirements def satisfy?(y) unless y.kind_of?(RPMDependency) raise ArgumentError, "Expecting an RPMDependency object" end x = self # Easy! if x.name != y.name return false end # Partial compare # # eg: x.version 2.3 == y.version 2.3-1 sense = x.version.partial_compare(y.version) # Thanks to rpmdsCompare() rpmds.c if sense < 0 and (x.flag == :> || x.flag == :>=) || (y.flag == :<= || y.flag == :<) return true elsif sense > 0 and (x.flag == :< || x.flag == :<=) || (y.flag == :>= || y.flag == :>) return true elsif sense == 0 and ( ((x.flag == :== or x.flag == :<= or x.flag == :>=) and (y.flag == :== or y.flag == :<= or y.flag == :>=)) or (x.flag == :< and y.flag == :<) or (x.flag == :> and y.flag == :>) ) return true end return false end end class RPMProvide < RPMDependency; end class RPMRequire < RPMDependency; end class RPMDbPackage < RPMPackage # , installed, available def initialize(*args) @repoid = args.pop # state @available = args.pop @installed = args.pop super(*args) end attr_reader :repoid, :available, :installed end # Simple storage for RPMPackage objects - keeps them unique and sorted class RPMDb def initialize # package name => [ RPMPackage, RPMPackage ] of different versions @rpms = Hash.new # package nevra => RPMPackage for lookups @index = Hash.new # provide name (aka feature) => [RPMPackage, RPMPackage] each providing this feature @provides = Hash.new # RPMPackages listed as available @available = Set.new # RPMPackages listed as installed @installed = Set.new end def [](package_name) self.lookup(package_name) end # Lookup package_name and return a descending array of package objects def lookup(package_name) pkgs = @rpms[package_name] if pkgs return pkgs.sort.reverse else return nil end end def lookup_provides(provide_name) @provides[provide_name] end # Using the package name as a key, and nevra for an index, keep a unique list of packages. # The available/installed state can be overwritten for existing packages. def push(*args) args.flatten.each do |new_rpm| unless new_rpm.kind_of?(RPMDbPackage) raise ArgumentError, "Expecting an RPMDbPackage object" end @rpms[new_rpm.n] ||= Array.new # we may already have this one, like when the installed list is refreshed idx = @index[new_rpm.nevra] if idx # grab the existing package if it's not curr_rpm = idx else @rpms[new_rpm.n] << new_rpm new_rpm.provides.each do |provide| @provides[provide.name] ||= Array.new @provides[provide.name] << new_rpm end curr_rpm = new_rpm end # Track the nevra -> RPMPackage association to avoid having to compare versions # with @rpms[new_rpm.n] on the next round @index[new_rpm.nevra] = curr_rpm # these are overwritten for existing packages if new_rpm.available @available << curr_rpm end if new_rpm.installed @installed << curr_rpm end end end def <<(*args) self.push(args) end def clear @rpms.clear @index.clear @provides.clear clear_available clear_installed end def clear_available @available.clear end def clear_installed @installed.clear end def size @rpms.size end alias :length :size def available_size @available.size end def installed_size @installed.size end def available?(package) @available.include?(package) end def installed?(package) @installed.include?(package) end def whatprovides(rpmdep) unless rpmdep.kind_of?(RPMDependency) raise ArgumentError, "Expecting an RPMDependency object" end what = [] packages = lookup_provides(rpmdep.name) if packages packages.each do |pkg| pkg.provides.each do |provide| if provide.satisfy?(rpmdep) what << pkg end end end end return what end end # Cache for our installed and available packages, pulled in from yum-dump.py class YumCache include Chef::Mixin::Command include Chef::Mixin::ShellOut include Singleton def initialize @rpmdb = RPMDb.new # Next time @rpmdb is accessed: # :all - Trigger a run of "yum-dump.py --options --installed-provides", updates # yum's cache and parses options from /etc/yum.conf. Pulls in Provides # dependency data for installed packages only - this data is slow to # gather. # :provides - Same as :all but pulls in Provides data for available packages as well. # Used as a last resort when we can't find a Provides match. # :installed - Trigger a run of "yum-dump.py --installed", only reads the local rpm # db. Used between client runs for a quick refresh. # :none - Do nothing, a call to one of the reload methods is required. @next_refresh = :all @allow_multi_install = [] @extra_repo_control = nil # these are for subsequent runs if we are on an interval Chef::Client.when_run_starts do YumCache.instance.reload end end attr_reader :extra_repo_control # Cache management # def refresh case @next_refresh when :none return nil when :installed reset_installed # fast opts=" --installed" when :all reset # medium opts=" --options --installed-provides" when :provides reset # slow! opts=" --options --all-provides" else raise ArgumentError, "Unexpected value in next_refresh: #{@next_refresh}" end if @extra_repo_control opts << " #{@extra_repo_control}" end one_line = false error = nil helper = ::File.join(::File.dirname(__FILE__), 'yum-dump.py') status = nil begin status = shell_out!("/usr/bin/python #{helper}#{opts}", :timeout => Chef::Config[:yum_timeout]) status.stdout.each_line do |line| one_line = true line.chomp! if line =~ %r{\[option (.*)\] (.*)} if $1 == "installonlypkgs" @allow_multi_install = $2.split else raise Chef::Exceptions::Package, "Strange, unknown option line '#{line}' from yum-dump.py" end next end if line =~ %r{^(\S+) ([0-9]+) (\S+) (\S+) (\S+) \[(.*)\] ([i,a,r]) (\S+)$} name = $1 epoch = $2 version = $3 release = $4 arch = $5 provides = parse_provides($6) type = $7 repoid = $8 else Chef::Log.warn("Problem parsing line '#{line}' from yum-dump.py! " + "Please check your yum configuration.") next end case type when "i" # if yum-dump was called with --installed this may not be true, but it's okay # since we don't touch the @available Set in reload_installed available = false installed = true when "a" available = true installed = false when "r" available = true installed = true end pkg = RPMDbPackage.new(name, epoch, version, release, arch, provides, installed, available, repoid) @rpmdb << pkg end error = status.stderr rescue Mixlib::ShellOut::CommandTimeout => e Chef::Log.error("#{helper} exceeded timeout #{Chef::Config[:yum_timeout]}") raise(e) end if status.exitstatus != 0 raise Chef::Exceptions::Package, "Yum failed - #{status.inspect} - returns: #{error}" else unless one_line Chef::Log.warn("Odd, no output from yum-dump.py. Please check " + "your yum configuration.") end end # A reload method must be called before the cache is altered @next_refresh = :none end def reload @next_refresh = :all end def reload_installed @next_refresh = :installed end def reload_provides @next_refresh = :provides end def reset @rpmdb.clear end def reset_installed @rpmdb.clear_installed end # Querying the cache # # Check for package by name or name+arch def package_available?(package_name) refresh if @rpmdb.lookup(package_name) return true else if package_name =~ %r{^(.*)\.(.*)$} pkg_name = $1 pkg_arch = $2 if matches = @rpmdb.lookup(pkg_name) matches.each do |m| return true if m.arch == pkg_arch end end end end return false end # Returns a array of packages satisfying an RPMDependency def packages_from_require(rpmdep) refresh @rpmdb.whatprovides(rpmdep) end # Check if a package-version.arch is available to install def version_available?(package_name, desired_version, arch=nil) version(package_name, arch, true, false) do |v| return true if desired_version == v end return false end # Return the source repository for a package-version.arch def package_repository(package_name, desired_version, arch=nil) package(package_name, arch, true, false) do |pkg| return pkg.repoid if desired_version == pkg.version.to_s end return nil end # Return the latest available version for a package.arch def available_version(package_name, arch=nil) version(package_name, arch, true, false) end alias :candidate_version :available_version # Return the currently installed version for a package.arch def installed_version(package_name, arch=nil) version(package_name, arch, false, true) end # Return an array of packages allowed to be installed multiple times, such as the kernel def allow_multi_install refresh @allow_multi_install end def enable_extra_repo_control(arg) # Don't touch cache if it's the same repos as the last load unless @extra_repo_control == arg @extra_repo_control = arg reload end end def disable_extra_repo_control # Only force reload when set if @extra_repo_control @extra_repo_control = nil reload end end private def version(package_name, arch=nil, is_available=false, is_installed=false) package(package_name, arch, is_available, is_installed) do |pkg| if block_given? yield pkg.version.to_s else # first match is latest version return pkg.version.to_s end end if block_given? return self else return nil end end def package(package_name, arch=nil, is_available=false, is_installed=false) refresh packages = @rpmdb[package_name] if packages packages.each do |pkg| if is_available next unless @rpmdb.available?(pkg) end if is_installed next unless @rpmdb.installed?(pkg) end if arch next unless pkg.arch == arch end if block_given? yield pkg else # first match is latest version return pkg end end end if block_given? return self else return nil end end # Parse provides from yum-dump.py output def parse_provides(string) ret = [] # ['atk = 1.12.2-1.fc6', 'libatk-1.0.so.0'] string.split(", ").each do |seg| # 'atk = 1.12.2-1.fc6' if seg =~ %r{^'(.*)'$} ret << RPMProvide.parse($1) end end return ret end end # YumCache include Chef::Mixin::GetSourceFromPackage include Chef::Mixin::ShellOut def initialize(new_resource, run_context) super @yum = YumCache.instance end # Extra attributes # def arch if @new_resource.respond_to?("arch") @new_resource.arch else nil end end def flush_cache if @new_resource.respond_to?("flush_cache") @new_resource.flush_cache else { :before => false, :after => false } end end def allow_downgrade if @new_resource.respond_to?("allow_downgrade") @new_resource.allow_downgrade else false end end # Helpers # def yum_arch arch ? ".#{arch}" : nil end def yum_command(command) status, stdout, stderr = output_of_command(command, {:timeout => Chef::Config[:yum_timeout]}) # This is fun: rpm can encounter errors in the %post/%postun scripts which aren't # considered fatal - meaning the rpm is still successfully installed. These issue # cause yum to emit a non fatal warning but still exit(1). As there's currently no # way to suppress this behavior and an exit(1) will break a Chef run we make an # effort to trap these and re-run the same install command - it will either fail a # second time or succeed. # # A cleaner solution would have to be done in python and better hook into # yum/rpm to handle exceptions as we see fit. if status.exitstatus == 1 stdout.each_line do |l| # rpm-4.4.2.3 lib/psm.c line 2182 if l =~ %r{^error: %(post|postun)\(.*\) scriptlet failed, exit status \d+$} Chef::Log.warn("#{@new_resource} caught non-fatal scriptlet issue: \"#{l}\". Can't trust yum exit status " + "so running install again to verify.") status, stdout, stderr = output_of_command(command, {:timeout => Chef::Config[:yum_timeout]}) break end end end if status.exitstatus > 0 command_output = "STDOUT: #{stdout}" command_output << "STDERR: #{stderr}" handle_command_failures(status, command_output, {}) end end # Standard Provider methods for Parent # def load_current_resource if flush_cache[:before] @yum.reload end if @new_resource.options repo_control = [] @new_resource.options.split.each do |opt| if opt =~ %r{--(enable|disable)repo=.+} repo_control << opt end end if repo_control.size > 0 @yum.enable_extra_repo_control(repo_control.join(" ")) else @yum.disable_extra_repo_control end else @yum.disable_extra_repo_control end # At this point package_name could be: # # 1) a package name, eg: "foo" # 2) a package name.arch, eg: "foo.i386" # 3) or a dependency, eg: "foo >= 1.1" # Check if we have name or name+arch which has a priority over a dependency unless @yum.package_available?(@new_resource.package_name) # If they aren't in the installed packages they could be a dependency parse_dependency end # Don't overwrite an existing arch unless arch parse_arch end @current_resource = Chef::Resource::Package.new(@new_resource.name) @current_resource.package_name(@new_resource.package_name) if @new_resource.source unless ::File.exists?(@new_resource.source) raise Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}" end Chef::Log.debug("#{@new_resource} checking rpm status") shell_out!("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@new_resource.source}", :timeout => Chef::Config[:yum_timeout]).stdout.each_line do |line| case line when /([\w\d_.-]+)\s([\w\d_.-]+)/ @current_resource.package_name($1) @new_resource.version($2) end end end if @new_resource.version new_resource = "#{@new_resource.package_name}-#{@new_resource.version}#{yum_arch}" else new_resource = "#{@new_resource.package_name}#{yum_arch}" end Chef::Log.debug("#{@new_resource} checking yum info for #{new_resource}") installed_version = @yum.installed_version(@new_resource.package_name, arch) @current_resource.version(installed_version) @candidate_version = @yum.candidate_version(@new_resource.package_name, arch) Chef::Log.debug("#{@new_resource} installed version: #{installed_version || "(none)"} candidate version: " + "#{@candidate_version || "(none)"}") @current_resource end def install_package(name, version) if @new_resource.source yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} localinstall #{@new_resource.source}") else # Work around yum not exiting with an error if a package doesn't exist for CHEF-2062 if @yum.version_available?(name, version, arch) method = "install" log_method = "installing" # More Yum fun: # # yum install of an old name+version will exit(1) # yum install of an old name+version+arch will exit(0) for some reason # # Some packages can be installed multiple times like the kernel unless @yum.allow_multi_install.include?(name) if RPMVersion.parse(@current_resource.version) > RPMVersion.parse(version) # Unless they want this... if allow_downgrade method = "downgrade" log_method = "downgrading" else # we bail like yum when the package is older raise Chef::Exceptions::Package, "Installed package #{name}-#{@current_resource.version} is newer " + "than candidate package #{name}-#{version}" end end end repo = @yum.package_repository(name, version, arch) Chef::Log.info("#{@new_resource} #{log_method} #{name}-#{version}#{yum_arch} from #{repo} repository") yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} #{method} #{name}-#{version}#{yum_arch}") else raise Chef::Exceptions::Package, "Version #{version} of #{name} not found. Did you specify both version " + "and release? (version-release, e.g. 1.84-10.fc6)" end end if flush_cache[:after] @yum.reload else @yum.reload_installed end end # Keep upgrades from trying to install an older candidate version. Can happen when a new # version is installed then removed from a repository, now the older available version # shows up as a viable install candidate. # # Can be done in upgrade_package but an upgraded from->to log message slips out # # Hacky - better overall solution? Custom compare in Package provider? def action_upgrade # Could be uninstalled or have no candidate if @current_resource.version.nil? || candidate_version.nil? super # Ensure the candidate is newer elsif RPMVersion.parse(candidate_version) > RPMVersion.parse(@current_resource.version) super else Chef::Log.debug("#{@new_resource} is at the latest version - nothing to do") end end def upgrade_package(name, version) install_package(name, version) end def remove_package(name, version) if version yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} remove #{name}-#{version}#{yum_arch}") else yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} remove #{name}#{yum_arch}") end if flush_cache[:after] @yum.reload else @yum.reload_installed end end def purge_package(name, version) remove_package(name, version) end private def parse_arch # Allow for foo.x86_64 style package_name like yum uses in it's output # if @new_resource.package_name =~ %r{^(.*)\.(.*)$} new_package_name = $1 new_arch = $2 # foo.i386 and foo.beta1 are both valid package names or expressions of an arch. # Ensure we don't have an existing package matching package_name, then ensure we at # least have a match for the new_package+new_arch before we overwrite. If neither # then fall through to standard package handling. if (@yum.installed_version(@new_resource.package_name).nil? and @yum.candidate_version(@new_resource.package_name).nil?) and (@yum.installed_version(new_package_name, new_arch) or @yum.candidate_version(new_package_name, new_arch)) @new_resource.package_name(new_package_name) @new_resource.arch(new_arch) end end end # If we don't have the package we could have been passed a 'whatprovides' feature # # eg: yum install "perl(Config)" # yum install "mtr = 2:0.71-3.1" # yum install "mtr > 2:0.71" # # We support resolving these out of the Provides data imported from yum-dump.py and # matching them up with an actual package so the standard resource handling can apply. # # There is currently no support for filename matching. def parse_dependency # Transform the package_name into a requirement yum_require = RPMRequire.parse(@new_resource.package_name) # and gather all the packages that have a Provides feature satisfying the requirement. # It could be multiple be we can only manage one packages = @yum.packages_from_require(yum_require) if packages.empty? # Don't bother if we are just ensuring a package is removed - we don't need Provides data actions = Array(@new_resource.action) unless actions.size == 1 and (actions[0] == :remove || actions[0] == :purge) Chef::Log.debug("#{@new_resource} couldn't match #{@new_resource.package_name} in " + "installed Provides, loading available Provides - this may take a moment") @yum.reload_provides packages = @yum.packages_from_require(yum_require) end end unless packages.empty? new_package_name = packages.first.name Chef::Log.debug("#{@new_resource} no package found for #{@new_resource.package_name} " + "but matched Provides for #{new_package_name}") # Ensure it's not the same package under a different architecture unique_names = [] packages.each do |pkg| unique_names << "#{pkg.name}-#{pkg.version.evr}" end unique_names.uniq! if unique_names.size > 1 Chef::Log.warn("#{@new_resource} matched multiple Provides for #{@new_resource.package_name} " + "but we can only use the first match: #{new_package_name}. Please use a more " + "specific version.") end @new_resource.package_name(new_package_name) end end end end end end chef-11.8.2/lib/chef/provider/package/yum-dump.py0000644000004100000410000002252212254362222021572 0ustar www-datawww-data# # Author:: Matthew Kent () # Copyright:: Copyright (c) 2009, 2011 Matthew Kent # License:: Apache License, Version 2.0 # # 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. # # yum-dump.py # Inspired by yumhelper.py by David Lutterkort # # Produce a list of installed, available and re-installable packages using yum # and dump the results to stdout. # # yum-dump invokes yum similarly to the command line interface which makes it # subject to most of the configuration paramaters in yum.conf. yum-dump will # also load yum plugins in the same manor as yum - these can affect the output. # # Can be run as non root, but that won't update the cache. # # Intended to support yum 2.x and 3.x import os import sys import time import yum import re import errno from yum import Errors from optparse import OptionParser from distutils import version YUM_PID_FILE='/var/run/yum.pid' # Seconds to wait for exclusive access to yum LOCK_TIMEOUT = 10 YUM_VER = version.StrictVersion(yum.__version__) YUM_MAJOR = YUM_VER.version[0] if YUM_MAJOR > 3 or YUM_MAJOR < 2: print >> sys.stderr, "yum-dump Error: Can't match supported yum version" \ " (%s)" % yum.__version__ sys.exit(1) # Required for Provides output if YUM_MAJOR == 2: import rpm import rpmUtils.miscutils def setup(yb, options): # Only want our output # if YUM_MAJOR == 3: try: if YUM_VER >= version.StrictVersion("3.2.22"): yb.preconf.errorlevel=0 yb.preconf.debuglevel=0 # initialize the config yb.conf else: yb.doConfigSetup(errorlevel=0, debuglevel=0) except yum.Errors.ConfigError, e: # supresses an ignored exception at exit yb.preconf = None print >> sys.stderr, "yum-dump Config Error: %s" % e return 1 except ValueError, e: yb.preconf = None print >> sys.stderr, "yum-dump Options Error: %s" % e return 1 elif YUM_MAJOR == 2: yb.doConfigSetup() def __log(a,b): pass yb.log = __log yb.errorlog = __log # Give Chef every possible package version, it can decide what to do with them if YUM_MAJOR == 3: yb.conf.showdupesfromrepos = True elif YUM_MAJOR == 2: yb.conf.setConfigOption('showdupesfromrepos', True) # Optionally run only on cached repositories, but non root must use the cache if os.geteuid() != 0: if YUM_MAJOR == 3: yb.conf.cache = True elif YUM_MAJOR == 2: yb.conf.setConfigOption('cache', True) else: if YUM_MAJOR == 3: yb.conf.cache = options.cache elif YUM_MAJOR == 2: yb.conf.setConfigOption('cache', options.cache) # Handle repo toggle via id or glob exactly like yum for opt, repos in options.repo_control: for repo in repos: if opt == '--enablerepo': yb.repos.enableRepo(repo) elif opt == '--disablerepo': yb.repos.disableRepo(repo) return 0 def dump_packages(yb, list, output_provides): packages = {} if YUM_MAJOR == 2: yb.doTsSetup() yb.doRepoSetup() yb.doSackSetup() db = yb.doPackageLists(list) for pkg in db.installed: pkg.type = 'i' packages[str(pkg)] = pkg if YUM_VER >= version.StrictVersion("3.2.21"): for pkg in db.available: pkg.type = 'a' packages[str(pkg)] = pkg # These are both installed and available for pkg in db.reinstall_available: pkg.type = 'r' packages[str(pkg)] = pkg else: # Old style method - no reinstall list for pkg in yb.pkgSack.returnPackages(): if str(pkg) in packages: if packages[str(pkg)].type == "i": packages[str(pkg)].type = 'r' continue pkg.type = 'a' packages[str(pkg)] = pkg unique_packages = packages.values() unique_packages.sort(lambda x, y: cmp(x.name, y.name)) for pkg in unique_packages: if output_provides == "all" or \ (output_provides == "installed" and (pkg.type == "i" or pkg.type == "r")): # yum 2 doesn't have provides_print, implement it ourselves using methods # based on requires gathering in packages.py if YUM_MAJOR == 2: provlist = [] # Installed and available are gathered in different ways if pkg.type == 'i' or pkg.type == 'r': names = pkg.hdr[rpm.RPMTAG_PROVIDENAME] flags = pkg.hdr[rpm.RPMTAG_PROVIDEFLAGS] ver = pkg.hdr[rpm.RPMTAG_PROVIDEVERSION] if names is not None: tmplst = zip(names, flags, ver) for (n, f, v) in tmplst: prov = rpmUtils.miscutils.formatRequire(n, v, f) provlist.append(prov) # This is slow :( elif pkg.type == 'a': for prcoTuple in pkg.returnPrco('provides'): prcostr = pkg.prcoPrintable(prcoTuple) provlist.append(prcostr) provides = provlist else: provides = pkg.provides_print else: provides = "[]" print '%s %s %s %s %s %s %s %s' % ( pkg.name, pkg.epoch, pkg.version, pkg.release, pkg.arch, provides, pkg.type, pkg.repoid ) return 0 def yum_dump(options): lock_obtained = False yb = yum.YumBase() status = setup(yb, options) if status != 0: return status if options.output_options: print "[option installonlypkgs] %s" % " ".join(yb.conf.installonlypkgs) # Non root can't handle locking on rhel/centos 4 if os.geteuid() != 0: return dump_packages(yb, options.package_list, options.output_provides) # Wrap the collection and output of packages in yum's global lock to prevent # any inconsistencies. try: # Spin up to LOCK_TIMEOUT countdown = LOCK_TIMEOUT while True: try: yb.doLock(YUM_PID_FILE) lock_obtained = True except Errors.LockError, e: time.sleep(1) countdown -= 1 if countdown == 0: print >> sys.stderr, "yum-dump Locking Error! Couldn't obtain an " \ "exclusive yum lock in %d seconds. Giving up." % LOCK_TIMEOUT return 200 else: break return dump_packages(yb, options.package_list, options.output_provides) # Ensure we clear the lock and cleanup any resources finally: try: yb.closeRpmDB() if lock_obtained == True: yb.doUnlock(YUM_PID_FILE) except Errors.LockError, e: print >> sys.stderr, "yum-dump Unlock Error: %s" % e return 200 # Preserve order of enable/disable repo args like yum does def gather_repo_opts(option, opt, value, parser): if getattr(parser.values, option.dest, None) is None: setattr(parser.values, option.dest, []) getattr(parser.values, option.dest).append((opt, value.split(','))) def main(): usage = "Usage: %prog [options]\n" + \ "Output a list of installed, available and re-installable packages via yum" parser = OptionParser(usage=usage) parser.add_option("-C", "--cache", action="store_true", dest="cache", default=False, help="run entirely from cache, don't update cache") parser.add_option("-o", "--options", action="store_true", dest="output_options", default=False, help="output select yum options useful to Chef") parser.add_option("-p", "--installed-provides", action="store_const", const="installed", dest="output_provides", default="none", help="output Provides for installed packages, big/wide output") parser.add_option("-P", "--all-provides", action="store_const", const="all", dest="output_provides", default="none", help="output Provides for all package, slow, big/wide output") parser.add_option("-i", "--installed", action="store_const", const="installed", dest="package_list", default="all", help="output only installed packages") parser.add_option("-a", "--available", action="store_const", const="available", dest="package_list", default="all", help="output only available and re-installable packages") parser.add_option("--enablerepo", action="callback", callback=gather_repo_opts, type="string", dest="repo_control", default=[], help="enable disabled repositories by id or glob") parser.add_option("--disablerepo", action="callback", callback=gather_repo_opts, type="string", dest="repo_control", default=[], help="disable repositories by id or glob") (options, args) = parser.parse_args() try: return yum_dump(options) except yum.Errors.RepoError, e: print >> sys.stderr, "yum-dump Repository Error: %s" % e return 1 except yum.Errors.YumBaseError, e: print >> sys.stderr, "yum-dump General Error: %s" % e return 1 try: status = main() # Suppress a nasty broken pipe error when output is piped to utilities like 'head' except IOError, e: if e.errno == errno.EPIPE: sys.exit(1) else: raise sys.exit(status) chef-11.8.2/lib/chef/provider/package/easy_install.rb0000644000004100000410000001066112254362222022460 0ustar www-datawww-data# # Author:: Joe Williams () # Copyright:: Copyright (c) 2009 Joe Williams # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/package' require 'chef/mixin/command' require 'chef/mixin/shell_out' require 'chef/resource/package' require 'chef/mixin/shell_out' class Chef class Provider class Package class EasyInstall < Chef::Provider::Package include Chef::Mixin::ShellOut def install_check(name) check = false begin # first check to see if we can import it output = shell_out!("#{python_binary_path} -c \"import #{name}\"", :returns=>[0,1]).stderr if output.include? "ImportError" # then check to see if its on the path output = shell_out!("#{python_binary_path} -c \"import sys; print sys.path\"", :returns=>[0,1]).stdout if output.downcase.include? "#{name.downcase}" check = true end else check = true end rescue # it's probably not installed end check end def easy_install_binary_path path = @new_resource.easy_install_binary path ? path : 'easy_install' end def python_binary_path path = @new_resource.python_binary path ? path : 'python' end def module_name m = @new_resource.module_name m ? m : @new_resource.name end def load_current_resource @current_resource = Chef::Resource::Package.new(@new_resource.name) @current_resource.package_name(@new_resource.package_name) @current_resource.version(nil) # get the currently installed version if installed package_version = nil if install_check(module_name) begin output = shell_out!("#{python_binary_path} -c \"import #{module_name}; print #{module_name}.__version__\"").stdout package_version = output.strip rescue output = shell_out!("#{python_binary_path} -c \"import sys; print sys.path\"", :returns=>[0,1]).stdout output_array = output.gsub(/[\[\]]/,'').split(/\s*,\s*/) package_path = "" output_array.each do |entry| if entry.downcase.include?(@new_resource.package_name) package_path = entry end end package_path[/\S\S(.*)\/(.*)-(.*)-py(.*).egg\S/] package_version = $3 end end if package_version == @new_resource.version Chef::Log.debug("#{@new_resource} at version #{@new_resource.version}") @current_resource.version(@new_resource.version) else Chef::Log.debug("#{@new_resource} at version #{package_version}") @current_resource.version(package_version) end @current_resource end def candidate_version return @candidate_version if @candidate_version # do a dry run to get the latest version result = shell_out!("#{easy_install_binary_path} -n #{@new_resource.package_name}", :returns=>[0,1]) @candidate_version = result.stdout[/(.*)Best match: (.*) (.*)$/, 3] @candidate_version end def install_package(name, version) run_command(:command => "#{easy_install_binary_path}#{expand_options(@new_resource.options)} \"#{name}==#{version}\"") end def upgrade_package(name, version) install_package(name, version) end def remove_package(name, version) run_command(:command => "#{easy_install_binary_path }#{expand_options(@new_resource.options)} -m #{name}") end def purge_package(name, version) remove_package(name, version) end end end end end chef-11.8.2/lib/chef/provider/package/solaris.rb0000644000004100000410000001352212254362222021444 0ustar www-datawww-data# # Author:: Toomas Pelberg () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/package' require 'chef/mixin/command' require 'chef/resource/package' require 'chef/mixin/get_source_from_package' class Chef class Provider class Package class Solaris < Chef::Provider::Package include Chef::Mixin::GetSourceFromPackage # def initialize(*args) # super # @current_resource = Chef::Resource::Package.new(@new_resource.name) # end def define_resource_requirements super requirements.assert(:install) do |a| a.assertion { @new_resource.source } a.failure_message Chef::Exceptions::Package, "Source for package #{@new_resource.name} required for action install" end requirements.assert(:all_actions) do |a| a.assertion { !@new_resource.source || @package_source_found } a.failure_message Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}" a.whyrun "would assume #{@new_resource.source} would be have previously been made available" end end def load_current_resource @current_resource = Chef::Resource::Package.new(@new_resource.name) @current_resource.package_name(@new_resource.package_name) @new_resource.version(nil) if @new_resource.source @package_source_found = ::File.exists?(@new_resource.source) if @package_source_found Chef::Log.debug("#{@new_resource} checking pkg status") status = popen4("pkginfo -l -d #{@new_resource.source} #{@new_resource.package_name}") do |pid, stdin, stdout, stderr| stdout.each do |line| case line when /VERSION:\s+(.+)/ @new_resource.version($1) end end end end end Chef::Log.debug("#{@new_resource} checking install state") status = popen4("pkginfo -l #{@current_resource.package_name}") do |pid, stdin, stdout, stderr| stdout.each do |line| case line when /VERSION:\s+(.+)/ Chef::Log.debug("#{@new_resource} version #{$1} is already installed") @current_resource.version($1) end end end unless status.exitstatus == 0 || status.exitstatus == 1 raise Chef::Exceptions::Package, "pkginfo failed - #{status.inspect}!" end unless @current_resource.version.nil? @current_resource.version(nil) end @current_resource end def candidate_version return @candidate_version if @candidate_version status = popen4("pkginfo -l -d #{@new_resource.source} #{new_resource.package_name}") do |pid, stdin, stdout, stderr| stdout.each_line do |line| case line when /VERSION:\s+(.+)/ @candidate_version = $1 @new_resource.version($1) Chef::Log.debug("#{@new_resource} setting install candidate version to #{@candidate_version}") end end end unless status.exitstatus == 0 raise Chef::Exceptions::Package, "pkginfo -l -d #{@new_resource.source} - #{status.inspect}!" end @candidate_version end def install_package(name, version) Chef::Log.debug("#{@new_resource} package install options: #{@new_resource.options}") if @new_resource.options.nil? if ::File.directory?(@new_resource.source) # CHEF-4469 command = "pkgadd -n -d #{@new_resource.source} #{@new_resource.package_name}" else command = "pkgadd -n -d #{@new_resource.source} all" end run_command_with_systems_locale( :command => command ) Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}") else if ::File.directory?(@new_resource.source) # CHEF-4469 command = "pkgadd -n#{expand_options(@new_resource.options)} -d #{@new_resource.source} #{@new_resource.package_name}" else command = "pkgadd -n#{expand_options(@new_resource.options)} -d #{@new_resource.source} all" end run_command_with_systems_locale( :command => command ) Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}") end end def remove_package(name, version) if @new_resource.options.nil? run_command_with_systems_locale( :command => "pkgrm -n #{name}" ) Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}") else run_command_with_systems_locale( :command => "pkgrm -n#{expand_options(@new_resource.options)} #{name}" ) Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}") end end end end end end chef-11.8.2/lib/chef/provider/package/macports.rb0000644000004100000410000000720612254362222021622 0ustar www-datawww-dataclass Chef class Provider class Package class Macports < Chef::Provider::Package def load_current_resource @current_resource = Chef::Resource::Package.new(@new_resource.name) @current_resource.package_name(@new_resource.package_name) @current_resource.version(current_installed_version) Chef::Log.debug("#{@new_resource} current version is #{@current_resource.version}") if @current_resource.version @candidate_version = macports_candidate_version if !@new_resource.version and !@candidate_version raise Chef::Exceptions::Package, "Could not get a candidate version for this package -- #{@new_resource.name} does not seem to be a valid package!" end Chef::Log.debug("#{@new_resource} candidate version is #{@candidate_version}") if @candidate_version @current_resource end def current_installed_version command = "port installed #{@new_resource.package_name}" output = get_response_from_command(command) response = nil output.each_line do |line| match = line.match(/^.+ @([^\s]+) \(active\)$/) response = match[1] if match end response end def macports_candidate_version command = "port info --version #{@new_resource.package_name}" output = get_response_from_command(command) match = output.match(/^version: (.+)$/) match ? match[1] : nil end def install_package(name, version) unless @current_resource.version == version command = "port#{expand_options(@new_resource.options)} install #{name}" command << " @#{version}" if version and !version.empty? run_command_with_systems_locale( :command => command ) end end def purge_package(name, version) command = "port#{expand_options(@new_resource.options)} uninstall #{name}" command << " @#{version}" if version and !version.empty? run_command_with_systems_locale( :command => command ) end def remove_package(name, version) command = "port#{expand_options(@new_resource.options)} deactivate #{name}" command << " @#{version}" if version and !version.empty? run_command_with_systems_locale( :command => command ) end def upgrade_package(name, version) # Saving this to a variable -- weird rSpec behavior # happens otherwise... current_version = @current_resource.version if current_version.nil? or current_version.empty? # Macports doesn't like when you upgrade a package # that hasn't been installed. install_package(name, version) elsif current_version != version run_command_with_systems_locale( :command => "port#{expand_options(@new_resource.options)} upgrade #{name} @#{version}" ) end end private def get_response_from_command(command) output = nil status = popen4(command) do |pid, stdin, stdout, stderr| begin output = stdout.read rescue Exception raise Chef::Exceptions::Package, "Could not read from STDOUT on command: #{command}" end end unless status.exitstatus == 0 || status.exitstatus == 1 raise Chef::Exceptions::Package, "#{command} failed - #{status.insect}!" end output end end end end end chef-11.8.2/lib/chef/provider/package/rubygems.rb0000644000004100000410000005330012254362222021623 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008, 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/package' require 'chef/mixin/command' require 'chef/resource/package' require 'chef/mixin/get_source_from_package' # Class methods on Gem are defined in rubygems require 'rubygems' # Ruby 1.9's gem_prelude can interact poorly with loading the full rubygems # explicitly like this. Make sure rubygems/specification is always last in this # list require 'rubygems/version' require 'rubygems/dependency' require 'rubygems/spec_fetcher' require 'rubygems/platform' # Compatibility note: Rubygems 2.0 removes rubygems/format in favor of # rubygems/package. begin require 'rubygems/format' rescue LoadError require 'rubygems/package' end require 'rubygems/dependency_installer' require 'rubygems/uninstaller' require 'rubygems/specification' class Chef class Provider class Package class Rubygems < Chef::Provider::Package class GemEnvironment # HACK: trigger gem config load early. Otherwise it can get lazy # loaded during operations where we've set Gem.sources to an # alternate value and overwrite it with the defaults. Gem.configuration DEFAULT_UNINSTALLER_OPTS = {:ignore => true, :executables => true} ## # The paths where rubygems should search for installed gems. # Implemented by subclasses. def gem_paths raise NotImplementedError end ## # A rubygems source index containing the list of gemspecs for all # available gems in the gem installation. # Implemented by subclasses # === Returns # Gem::SourceIndex def gem_source_index raise NotImplementedError end ## # A rubygems specification object containing the list of gemspecs for all # available gems in the gem installation. # Implemented by subclasses # For rubygems >= 1.8.0 # === Returns # Gem::Specification def gem_specification raise NotImplementedError end ## # Lists the installed versions of +gem_name+, constrained by the # version spec in +gem_dep+ # === Arguments # Gem::Dependency +gem_dep+ is a Gem::Dependency object, its version # specification constrains which gems are returned. # === Returns # [Gem::Specification] an array of Gem::Specification objects def installed_versions(gem_dep) if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.8.0') gem_specification.find_all_by_name(gem_dep.name, gem_dep.requirement) else gem_source_index.search(gem_dep) end end ## # Yields to the provided block with rubygems' source list set to the # list provided. Always resets the list when the block returns or # raises an exception. def with_gem_sources(*sources) sources.compact! original_sources = Gem.sources Gem.sources = sources unless sources.empty? yield ensure Gem.sources = original_sources end ## # Extracts the gemspec from a (on-disk) gem package. # === Returns # Gem::Specification # #-- # Compatibility note: Rubygems 1.x uses Gem::Format, 2.0 moved this # code into Gem::Package. def spec_from_file(file) if defined?(Gem::Format) and Gem::Package.respond_to?(:open) Gem::Format.from_file_by_path(file).spec else Gem::Package.new(file).spec end end ## # Determines the candidate version for a gem from a .gem file on disk # and checks if it matches the version contraints in +gem_dependency+ # === Returns # Gem::Version a singular gem version object is returned if the gem # is available # nil returns nil if the gem on disk doesn't match the # version constraints for +gem_dependency+ def candidate_version_from_file(gem_dependency, source) spec = spec_from_file(source) if spec.satisfies_requirement?(gem_dependency) logger.debug {"#{@new_resource} found candidate gem version #{spec.version} from local gem package #{source}"} spec.version else # This is probably going to end badly... logger.warn { "#{@new_resource} gem package #{source} does not satisfy the requirements #{gem_dependency.to_s}" } nil end end ## # Finds the newest version that satisfies the constraints of # +gem_dependency+. The version is determined from the cache or a # round-trip to the server as needed. The architecture and gem # sources will be set before making the query. # === Returns # Gem::Version a singular gem version object is returned if the gem # is available # nil returns nil if the gem could not be found def candidate_version_from_remote(gem_dependency, *sources) raise NotImplementedError end ## # Find the newest gem version available from Gem.sources that satisfies # the constraints of +gem_dependency+ def find_newest_remote_version(gem_dependency, *sources) available_gems = dependency_installer.find_gems_with_sources(gem_dependency) spec, source = if available_gems.respond_to?(:last) # DependencyInstaller sorts the results such that the last one is # always the one it considers best. spec_with_source = available_gems.last spec_with_source && spec_with_source else # Rubygems 2.0 returns a Gem::Available set, which is a # collection of AvailableSet::Tuple structs available_gems.pick_best! best_gem = available_gems.set.first best_gem && [best_gem.spec, best_gem.source] end version = spec && spec.version if version logger.debug { "#{@new_resource} found gem #{spec.name} version #{version} for platform #{spec.platform} from #{source}" } version else source_list = sources.compact.empty? ? "[#{Gem.sources.to_a.join(', ')}]" : "[#{sources.join(', ')}]" logger.warn { "#{@new_resource} failed to find gem #{gem_dependency} from #{source_list}" } nil end end ## # Installs a gem via the rubygems ruby API. # === Options # :sources rubygems servers to use # Other options are passed to Gem::DependencyInstaller.new def install(gem_dependency, options={}) with_gem_sources(*options.delete(:sources)) do with_correct_verbosity do dependency_installer(options).install(gem_dependency) end end end ## # Uninstall the gem +gem_name+ via the rubygems ruby API. If # +gem_version+ is provided, only that version will be uninstalled. # Otherwise, all versions are uninstalled. # === Options # Options are passed to Gem::Uninstaller.new def uninstall(gem_name, gem_version=nil, opts={}) gem_version ? opts[:version] = gem_version : opts[:all] = true with_correct_verbosity do uninstaller(gem_name, opts).uninstall end end ## # Set rubygems' user interaction to ConsoleUI or SilentUI depending # on our current debug level def with_correct_verbosity Gem::DefaultUserInteraction.ui = Chef::Log.debug? ? Gem::ConsoleUI.new : Gem::SilentUI.new yield end def dependency_installer(opts={}) Gem::DependencyInstaller.new(opts) end def uninstaller(gem_name, opts={}) Gem::Uninstaller.new(gem_name, DEFAULT_UNINSTALLER_OPTS.merge(opts)) end private def logger Chef::Log.logger end end class CurrentGemEnvironment < GemEnvironment def gem_paths Gem.path end def gem_source_index Gem.source_index end def gem_specification Gem::Specification end def candidate_version_from_remote(gem_dependency, *sources) with_gem_sources(*sources) do find_newest_remote_version(gem_dependency, *sources) end end end class AlternateGemEnvironment < GemEnvironment JRUBY_PLATFORM = /(:?universal|x86_64|x86)\-java\-[0-9\.]+/ def self.gempath_cache @gempath_cache ||= {} end def self.platform_cache @platform_cache ||= {} end include Chef::Mixin::ShellOut attr_reader :gem_binary_location def initialize(gem_binary_location) @gem_binary_location = gem_binary_location end def gem_paths if self.class.gempath_cache.key?(@gem_binary_location) self.class.gempath_cache[@gem_binary_location] else # shellout! is a fork/exec which won't work on windows shell_style_paths = shell_out!("#{@gem_binary_location} env gempath").stdout # on windows, the path separator is (usually? always?) semicolon paths = shell_style_paths.split(::File::PATH_SEPARATOR).map { |path| path.strip } self.class.gempath_cache[@gem_binary_location] = paths end end def gem_source_index @source_index ||= Gem::SourceIndex.from_gems_in(*gem_paths.map { |p| p + '/specifications' }) end def gem_specification # Only once, dirs calls a reset unless @specification Gem::Specification.dirs = gem_paths @specification = Gem::Specification end @specification end ## # Attempt to detect the correct platform settings for the target gem # environment. # # In practice, this only makes a difference if different versions are # available depending on platform, and only if the target gem # environment has a radically different platform (i.e., jruby), so we # just try to detect jruby and fall back to the current platforms # (Gem.platforms) if we don't detect it. # # === Returns # [String|Gem::Platform] returns an array of Gem::Platform-compatible # objects, i.e., Strings that are valid for Gem::Platform or actual # Gem::Platform objects. def gem_platforms if self.class.platform_cache.key?(@gem_binary_location) self.class.platform_cache[@gem_binary_location] else gem_environment = shell_out!("#{@gem_binary_location} env").stdout if jruby = gem_environment[JRUBY_PLATFORM] self.class.platform_cache[@gem_binary_location] = ['ruby', Gem::Platform.new(jruby)] else self.class.platform_cache[@gem_binary_location] = Gem.platforms end end end def with_gem_platforms(*alt_gem_platforms) alt_gem_platforms.flatten! original_gem_platforms = Gem.platforms Gem.platforms = alt_gem_platforms yield ensure Gem.platforms = original_gem_platforms end def candidate_version_from_remote(gem_dependency, *sources) with_gem_sources(*sources) do with_gem_platforms(*gem_platforms) do find_newest_remote_version(gem_dependency, *sources) end end end end include Chef::Mixin::ShellOut attr_reader :gem_env attr_reader :cleanup_gem_env def logger Chef::Log.logger end include Chef::Mixin::GetSourceFromPackage def initialize(new_resource, run_context=nil) super @cleanup_gem_env = true if new_resource.gem_binary if new_resource.options && new_resource.options.kind_of?(Hash) msg = "options cannot be given as a hash when using an explicit gem_binary\n" msg << "in #{new_resource} from #{new_resource.source_line}" raise ArgumentError, msg end @gem_env = AlternateGemEnvironment.new(new_resource.gem_binary) Chef::Log.debug("#{@new_resource} using gem '#{new_resource.gem_binary}'") elsif is_omnibus? && (!@new_resource.instance_of? Chef::Resource::ChefGem) # Opscode Omnibus - The ruby that ships inside omnibus is only used for Chef # Default to installing somewhere more functional if new_resource.options && new_resource.options.kind_of?(Hash) msg = "options should be a string instead of a hash\n" msg << "in #{new_resource} from #{new_resource.source_line}" raise ArgumentError, msg end gem_location = find_gem_by_path @new_resource.gem_binary gem_location @gem_env = AlternateGemEnvironment.new(gem_location) Chef::Log.debug("#{@new_resource} using gem '#{gem_location}'") else @gem_env = CurrentGemEnvironment.new @cleanup_gem_env = false Chef::Log.debug("#{@new_resource} using gem from running ruby environment") end end def is_omnibus? if RbConfig::CONFIG['bindir'] =~ %r!/opt/(opscode|chef)/embedded/bin! Chef::Log.debug("#{@new_resource} detected omnibus installation in #{RbConfig::CONFIG['bindir']}") # Omnibus installs to a static path because of linking on unix, find it. true elsif RbConfig::CONFIG['bindir'].sub(/^[\w]:/, '') == "/opscode/chef/embedded/bin" Chef::Log.debug("#{@new_resource} detected omnibus installation in #{RbConfig::CONFIG['bindir']}") # windows, with the drive letter removed true else false end end def find_gem_by_path Chef::Log.debug("#{@new_resource} searching for 'gem' binary in path: #{ENV['PATH']}") separator = ::File::ALT_SEPARATOR ? ::File::ALT_SEPARATOR : ::File::SEPARATOR path_to_first_gem = ENV['PATH'].split(::File::PATH_SEPARATOR).select { |path| ::File.exists?(path + separator + "gem") }.first raise Chef::Exceptions::FileNotFound, "Unable to find 'gem' binary in path: #{ENV['PATH']}" if path_to_first_gem.nil? path_to_first_gem + separator + "gem" end def gem_dependency Gem::Dependency.new(@new_resource.package_name, @new_resource.version) end def source_is_remote? return true if @new_resource.source.nil? scheme = URI.parse(@new_resource.source).scheme # URI.parse gets confused by MS Windows paths with forward slashes. scheme = nil if scheme =~ /^[a-z]$/ %w{http https}.include?(scheme) rescue URI::InvalidURIError Chef::Log.debug("#{@new_resource} failed to parse source '#{@new_resource.source}' as a URI, assuming a local path") false end def current_version #raise 'todo' # If one or more matching versions are installed, the newest of them # is the current version if !matching_installed_versions.empty? gemspec = matching_installed_versions.last logger.debug { "#{@new_resource} found installed gem #{gemspec.name} version #{gemspec.version} matching #{gem_dependency}"} gemspec # If no version matching the requirements exists, the latest installed # version is the current version. elsif !all_installed_versions.empty? gemspec = all_installed_versions.last logger.debug { "#{@new_resource} newest installed version of gem #{gemspec.name} is #{gemspec.version}" } gemspec else logger.debug { "#{@new_resource} no installed version found for #{gem_dependency.to_s}"} nil end end def matching_installed_versions @matching_installed_versions ||= @gem_env.installed_versions(gem_dependency) end def all_installed_versions @all_installed_versions ||= begin @gem_env.installed_versions(Gem::Dependency.new(gem_dependency.name, '>= 0')) end end def gem_sources @new_resource.source ? Array(@new_resource.source) : nil end def load_current_resource @current_resource = Chef::Resource::Package::GemPackage.new(@new_resource.name) @current_resource.package_name(@new_resource.package_name) if current_spec = current_version @current_resource.version(current_spec.version.to_s) end @current_resource end def cleanup_after_converge if @cleanup_gem_env logger.debug { "#{@new_resource} resetting gem environment to default" } Gem.clear_paths end end def candidate_version @candidate_version ||= begin if target_version_already_installed? nil elsif source_is_remote? @gem_env.candidate_version_from_remote(gem_dependency, *gem_sources).to_s else @gem_env.candidate_version_from_file(gem_dependency, @new_resource.source).to_s end end end def target_version_already_installed? return false unless @current_resource && @current_resource.version return false if @current_resource.version.nil? Gem::Requirement.new(@new_resource.version).satisfied_by?(Gem::Version.new(@current_resource.version)) end ## # Installs the gem, using either the gems API or shelling out to `gem` # according to the following criteria: # 1. Use gems API (Gem::DependencyInstaller) by default # 2. shell out to `gem install` when a String of options is given # 3. use gems API with options if a hash of options is given def install_package(name, version) if source_is_remote? && @new_resource.gem_binary.nil? if @new_resource.options.nil? @gem_env.install(gem_dependency, :sources => gem_sources) elsif @new_resource.options.kind_of?(Hash) options = @new_resource.options options[:sources] = gem_sources @gem_env.install(gem_dependency, options) else install_via_gem_command(name, version) end elsif @new_resource.gem_binary.nil? @gem_env.install(@new_resource.source) else install_via_gem_command(name,version) end true end def gem_binary_path @new_resource.gem_binary || 'gem' end def install_via_gem_command(name, version) if @new_resource.source =~ /\.gem$/i name = @new_resource.source else src = @new_resource.source && " --source=#{@new_resource.source} --source=http://rubygems.org" end if version shell_out!("#{gem_binary_path} install #{name} -q --no-rdoc --no-ri -v \"#{version}\"#{src}#{opts}", :env=>nil) else shell_out!("#{gem_binary_path} install \"#{name}\" -q --no-rdoc --no-ri #{src}#{opts}", :env=>nil) end end def upgrade_package(name, version) install_package(name, version) end def remove_package(name, version) if @new_resource.gem_binary.nil? if @new_resource.options.nil? @gem_env.uninstall(name, version) elsif @new_resource.options.kind_of?(Hash) @gem_env.uninstall(name, version, @new_resource.options) else uninstall_via_gem_command(name, version) end else uninstall_via_gem_command(name, version) end end def uninstall_via_gem_command(name, version) if version shell_out!("#{gem_binary_path} uninstall #{name} -q -x -I -v \"#{version}\"#{opts}", :env=>nil) else shell_out!("#{gem_binary_path} uninstall #{name} -q -x -I -a#{opts}", :env=>nil) end end def purge_package(name, version) remove_package(name, version) end private def opts expand_options(@new_resource.options) end end end end end chef-11.8.2/lib/chef/provider/package/aix.rb0000644000004100000410000001350612254362222020553 0ustar www-datawww-data# # Author:: Deepali Jagtap # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # # require 'chef/provider/package' require 'chef/mixin/command' require 'chef/resource/package' require 'chef/mixin/get_source_from_package' class Chef class Provider class Package class Aix < Chef::Provider::Package include Chef::Mixin::GetSourceFromPackage def define_resource_requirements super requirements.assert(:install) do |a| a.assertion { @new_resource.source } a.failure_message Chef::Exceptions::Package, "Source for package #{@new_resource.name} required for action install" end requirements.assert(:all_actions) do |a| a.assertion { !@new_resource.source || @package_source_found } a.failure_message Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}" a.whyrun "would assume #{@new_resource.source} would be have previously been made available" end end def load_current_resource @current_resource = Chef::Resource::Package.new(@new_resource.name) @current_resource.package_name(@new_resource.package_name) @new_resource.version(nil) if @new_resource.source @package_source_found = ::File.exists?(@new_resource.source) if @package_source_found Chef::Log.debug("#{@new_resource} checking pkg status") status = popen4("installp -L -d #{@new_resource.source}") do |pid, stdin, stdout, stderr| package_found = false stdout.each do |line| case line when /#{@new_resource.package_name}:/ package_found = true fields = line.split(":") @new_resource.version(fields[2]) end end end end end Chef::Log.debug("#{@new_resource} checking install state") status = popen4("lslpp -lcq #{@current_resource.package_name}") do |pid, stdin, stdout, stderr| stdout.each do |line| case line when /#{@current_resource.package_name}/ fields = line.split(":") Chef::Log.debug("#{@new_resource} version #{fields[2]} is already installed") @current_resource.version(fields[2]) end end end unless status.exitstatus == 0 || status.exitstatus == 1 raise Chef::Exceptions::Package, "lslpp failed - #{status.inspect}!" end @current_resource end def candidate_version return @candidate_version if @candidate_version status = popen4("installp -L -d #{@new_resource.source}") do |pid, stdin, stdout, stderr| stdout.each_line do |line| case line when /\w:{Regexp.escape(@new_resource.package_name)}:(.*)/ fields = line.split(":") @candidate_version = fields[2] @new_resource.version(fields[2]) Chef::Log.debug("#{@new_resource} setting install candidate version to #{@candidate_version}") end end end unless status.exitstatus == 0 raise Chef::Exceptions::Package, "installp -L -d #{@new_resource.source} - #{status.inspect}!" end @candidate_version end # # The install/update action needs to be tested with various kinds of packages # on AIX viz. packages with or without licensing file dependencies, packages # with dependencies on other packages which will help to test additional # options of installp. # So far, the code has been tested only with standalone packages. # def install_package(name, version) Chef::Log.debug("#{@new_resource} package install options: #{@new_resource.options}") if @new_resource.options.nil? run_command_with_systems_locale( :command => "installp -aYF -d #{@new_resource.source} #{@new_resource.package_name}" ) Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}") else run_command_with_systems_locale( :command => "installp -aYF #{expand_options(@new_resource.options)} -d #{@new_resource.source} #{@new_resource.package_name}" ) Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}") end end alias_method :upgrade_package, :install_package def remove_package(name, version) if @new_resource.options.nil? run_command_with_systems_locale( :command => "installp -u #{name}" ) Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}") else run_command_with_systems_locale( :command => "installp -u #{expand_options(@new_resource.options)} #{name}" ) Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}") end end end end end end chef-11.8.2/lib/chef/provider/package/dpkg.rb0000644000004100000410000001125412254362222020715 0ustar www-datawww-data# # Author:: Bryan McLellan (btm@loftninjas.org) # Copyright:: Copyright (c) 2009 Bryan McLellan # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/package' require 'chef/mixin/command' require 'chef/resource/package' require 'chef/mixin/get_source_from_package' class Chef class Provider class Package class Dpkg < Chef::Provider::Package::Apt DPKG_INFO = /([a-z\d\-\+\.]+)\t([\w\d.~-]+)/ DPKG_INSTALLED = /^Status: install ok installed/ DPKG_VERSION = /^Version: (.+)$/ include Chef::Mixin::GetSourceFromPackage def define_resource_requirements super requirements.assert(:install) do |a| a.assertion{ not @new_resource.source.nil? } a.failure_message Chef::Exceptions::Package, "Source for package #{@new_resource.name} required for action install" end # TODO this was originally written for any action in which .source is provided # but would it make more sense to only look at source if the action is :install? requirements.assert(:all_actions) do |a| a.assertion { @source_exists } a.failure_message Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}" a.whyrun "Assuming it would have been previously downloaded." end end def load_current_resource @source_exists = true @current_resource = Chef::Resource::Package.new(@new_resource.name) @current_resource.package_name(@new_resource.package_name) @new_resource.version(nil) if @new_resource.source @source_exists = ::File.exists?(@new_resource.source) if @source_exists # Get information from the package if supplied Chef::Log.debug("#{@new_resource} checking dpkg status") status = popen4("dpkg-deb -W #{@new_resource.source}") do |pid, stdin, stdout, stderr| stdout.each_line do |line| if pkginfo = DPKG_INFO.match(line) @current_resource.package_name(pkginfo[1]) @new_resource.version(pkginfo[2]) end end end else # Source provided but not valid means we can't safely do further processing return end end # Check to see if it is installed package_installed = nil Chef::Log.debug("#{@new_resource} checking install state") status = popen4("dpkg -s #{@current_resource.package_name}") do |pid, stdin, stdout, stderr| stdout.each_line do |line| case line when DPKG_INSTALLED package_installed = true when DPKG_VERSION if package_installed Chef::Log.debug("#{@new_resource} current version is #{$1}") @current_resource.version($1) end end end end unless status.exitstatus == 0 || status.exitstatus == 1 raise Chef::Exceptions::Package, "dpkg failed - #{status.inspect}!" end @current_resource end def install_package(name, version) run_command_with_systems_locale( :command => "dpkg -i#{expand_options(@new_resource.options)} #{@new_resource.source}", :environment => { "DEBIAN_FRONTEND" => "noninteractive" } ) end def remove_package(name, version) run_command_with_systems_locale( :command => "dpkg -r#{expand_options(@new_resource.options)} #{@new_resource.package_name}", :environment => { "DEBIAN_FRONTEND" => "noninteractive" } ) end def purge_package(name, version) run_command_with_systems_locale( :command => "dpkg -P#{expand_options(@new_resource.options)} #{@new_resource.package_name}", :environment => { "DEBIAN_FRONTEND" => "noninteractive" } ) end end end end end chef-11.8.2/lib/chef/provider/package/rpm.rb0000644000004100000410000001036312254362222020566 0ustar www-datawww-data# # Author:: Joshua Timberman () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/package' require 'chef/mixin/command' require 'chef/resource/package' require 'chef/mixin/get_source_from_package' class Chef class Provider class Package class Rpm < Chef::Provider::Package include Chef::Mixin::GetSourceFromPackage def define_resource_requirements super requirements.assert(:all_actions) do |a| a.assertion { @package_source_exists } a.failure_message Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}" a.whyrun "Assuming package #{@new_resource.name} would have been made available." end requirements.assert(:all_actions) do |a| a.assertion { !@rpm_status.nil? && (@rpm_status.exitstatus == 0 || @rpm_status.exitstatus == 1) } a.failure_message Chef::Exceptions::Package, "Unable to determine current version due to RPM failure. Detail: #{@rpm_status.inspect}" a.whyrun "Assuming current version would have been determined for package#{@new_resource.name}." end end def load_current_resource @package_source_provided = true @package_source_exists = true @current_resource = Chef::Resource::Package.new(@new_resource.name) @current_resource.package_name(@new_resource.package_name) @new_resource.version(nil) if @new_resource.source unless ::File.exists?(@new_resource.source) @package_source_exists = false return end Chef::Log.debug("#{@new_resource} checking rpm status") status = popen4("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@new_resource.source}") do |pid, stdin, stdout, stderr| stdout.each do |line| case line when /([\w\d_.-]+)\s([\w\d_.-]+)/ @current_resource.package_name($1) @new_resource.version($2) end end end else if Array(@new_resource.action).include?(:install) @package_source_exists = false return end end Chef::Log.debug("#{@new_resource} checking install state") @rpm_status = popen4("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@current_resource.package_name}") do |pid, stdin, stdout, stderr| stdout.each do |line| case line when /([\w\d_.-]+)\s([\w\d_.-]+)/ Chef::Log.debug("#{@new_resource} current version is #{$2}") @current_resource.version($2) end end end @current_resource end def install_package(name, version) unless @current_resource.version run_command_with_systems_locale( :command => "rpm #{@new_resource.options} -i #{@new_resource.source}" ) else run_command_with_systems_locale( :command => "rpm #{@new_resource.options} -U #{@new_resource.source}" ) end end alias_method :upgrade_package, :install_package def remove_package(name, version) if version run_command_with_systems_locale( :command => "rpm #{@new_resource.options} -e #{name}-#{version}" ) else run_command_with_systems_locale( :command => "rpm #{@new_resource.options} -e #{name}" ) end end end end end end chef-11.8.2/lib/chef/provider/package/pacman.rb0000644000004100000410000000732412254362222021232 0ustar www-datawww-data# # Author:: Jan Zimmek () # Copyright:: Copyright (c) 2010 Jan Zimmek # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/package' require 'chef/mixin/command' require 'chef/resource/package' class Chef class Provider class Package class Pacman < Chef::Provider::Package def load_current_resource @current_resource = Chef::Resource::Package.new(@new_resource.name) @current_resource.package_name(@new_resource.package_name) @current_resource.version(nil) Chef::Log.debug("#{@new_resource} checking pacman for #{@new_resource.package_name}") status = popen4("pacman -Qi #{@new_resource.package_name}") do |pid, stdin, stdout, stderr| stdout.each do |line| line.force_encoding(Encoding::UTF_8) if line.respond_to?(:force_encoding) case line when /^Version(\s?)*: (.+)$/ Chef::Log.debug("#{@new_resource} current version is #{$2}") @current_resource.version($2) end end end unless status.exitstatus == 0 || status.exitstatus == 1 raise Chef::Exceptions::Package, "pacman failed - #{status.inspect}!" end @current_resource end def candidate_version return @candidate_version if @candidate_version repos = ["extra","core","community"] if(::File.exists?("/etc/pacman.conf")) pacman = ::File.read("/etc/pacman.conf") repos = pacman.scan(/\[(.+)\]/).flatten end package_repos = repos.map {|r| Regexp.escape(r) }.join('|') status = popen4("pacman -Ss #{@new_resource.package_name}") do |pid, stdin, stdout, stderr| stdout.each do |line| case line when /^(#{package_repos})\/#{Regexp.escape(@new_resource.package_name)} (.+)$/ # $2 contains a string like "4.4.0-1 (kde kdenetwork)" or "3.10-4 (base)" # simply split by space and use first token @candidate_version = $2.split(" ").first end end end unless status.exitstatus == 0 || status.exitstatus == 1 raise Chef::Exceptions::Package, "pacman failed - #{status.inspect}!" end unless @candidate_version raise Chef::Exceptions::Package, "pacman does not have a version of package #{@new_resource.package_name}" end @candidate_version end def install_package(name, version) run_command_with_systems_locale( :command => "pacman --sync --noconfirm --noprogressbar#{expand_options(@new_resource.options)} #{name}" ) end def upgrade_package(name, version) install_package(name, version) end def remove_package(name, version) run_command_with_systems_locale( :command => "pacman --remove --noconfirm --noprogressbar#{expand_options(@new_resource.options)} #{name}" ) end def purge_package(name, version) remove_package(name, version) end end end end end chef-11.8.2/lib/chef/provider/package/portage.rb0000644000004100000410000001144312254362222021431 0ustar www-datawww-data# # Author:: Ezra Zygmuntowicz () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/package' require 'chef/mixin/command' require 'chef/resource/package' class Chef class Provider class Package class Portage < Chef::Provider::Package PACKAGE_NAME_PATTERN = %r{(?:([^/]+)/)?([^/]+)} def load_current_resource @current_resource = Chef::Resource::Package.new(@new_resource.name) @current_resource.package_name(@new_resource.package_name) @current_resource.version(nil) category, pkg = %r{^#{PACKAGE_NAME_PATTERN}$}.match(@new_resource.package_name)[1,2] possibilities = Dir["/var/db/pkg/#{category || "*"}/#{pkg}-*"].map {|d| d.sub(%r{/var/db/pkg/}, "") } versions = possibilities.map do |entry| if(entry =~ %r{[^/]+/#{Regexp.escape(pkg)}\-(\d[\.\d]*((_(alpha|beta|pre|rc|p)\d*)*)?(-r\d+)?)}) [$&, $1] end end.compact if versions.size > 1 atoms = versions.map {|v| v.first }.sort categories = atoms.map {|v| v.split('/')[0] }.uniq if !category && categories.size > 1 raise Chef::Exceptions::Package, "Multiple packages found for #{@new_resource.package_name}: #{atoms.join(" ")}. Specify a category." end elsif versions.size == 1 @current_resource.version(versions.first.last) Chef::Log.debug("#{@new_resource} current version #{$1}") end @current_resource end def parse_emerge(package, txt) availables = {} found_package_name = nil txt.each_line do |line| if line =~ /\*\s+#{PACKAGE_NAME_PATTERN}/ found_package_name = $&.gsub(/\*/, '').strip if package =~ /\// #the category is specified if found_package_name == package availables[found_package_name] = nil end else #the category is not specified if found_package_name.split("/").last == package availables[found_package_name] = nil end end end if line =~ /Latest version available: (.*)/ && availables.has_key?(found_package_name) availables[found_package_name] = $1.strip end end if availables.size > 1 # shouldn't happen if a category is specified so just use `package` raise Chef::Exceptions::Package, "Multiple emerge results found for #{package}: #{availables.keys.join(" ")}. Specify a category." end availables.values.first end def candidate_version return @candidate_version if @candidate_version status = popen4("emerge --color n --nospinner --search #{@new_resource.package_name.split('/').last}") do |pid, stdin, stdout, stderr| available, installed = parse_emerge(@new_resource.package_name, stdout.read) @candidate_version = available end unless status.exitstatus == 0 raise Chef::Exceptions::Package, "emerge --search failed - #{status.inspect}!" end @candidate_version end def install_package(name, version) pkg = "=#{name}-#{version}" if(version =~ /^\~(.+)/) # If we start with a tilde pkg = "~#{name}-#{$1}" end run_command_with_systems_locale( :command => "emerge -g --color n --nospinner --quiet#{expand_options(@new_resource.options)} #{pkg}" ) end def upgrade_package(name, version) install_package(name, version) end def remove_package(name, version) if(version) pkg = "=#{@new_resource.package_name}-#{version}" else pkg = "#{@new_resource.package_name}" end run_command_with_systems_locale( :command => "emerge --unmerge --color n --nospinner --quiet#{expand_options(@new_resource.options)} #{pkg}" ) end def purge_package(name, version) remove_package(name, version) end end end end end chef-11.8.2/lib/chef/provider/service.rb0000644000004100000410000001214312254362222020033 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/mixin/command' require 'chef/provider' class Chef class Provider class Service < Chef::Provider include Chef::Mixin::Command def initialize(new_resource, run_context) super @enabled = nil end def whyrun_supported? true end def load_new_resource_state # If the user didn't specify a change in enabled state, # it will be the same as the old resource if ( @new_resource.enabled.nil? ) @new_resource.enabled(@current_resource.enabled) end if ( @new_resource.running.nil? ) @new_resource.running(@current_resource.running) end end def shared_resource_requirements end def define_resource_requirements requirements.assert(:reload) do |a| a.assertion { @new_resource.supports[:reload] || @new_resource.reload_command } a.failure_message Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :reload" # if a service is not declared to support reload, that won't # typically change during the course of a run - so no whyrun # alternative here. end end def action_enable if @current_resource.enabled Chef::Log.debug("#{@new_resource} already enabled - nothing to do") else converge_by("enable service #{@new_resource}") do enable_service Chef::Log.info("#{@new_resource} enabled") end end load_new_resource_state @new_resource.enabled(true) end def action_disable if @current_resource.enabled converge_by("disable service #{@new_resource}") do disable_service Chef::Log.info("#{@new_resource} disabled") end else Chef::Log.debug("#{@new_resource} already disabled - nothing to do") end load_new_resource_state @new_resource.enabled(false) end def action_start unless @current_resource.running converge_by("start service #{@new_resource}") do start_service Chef::Log.info("#{@new_resource} started") end else Chef::Log.debug("#{@new_resource} already running - nothing to do") end load_new_resource_state @new_resource.running(true) end def action_stop if @current_resource.running converge_by("stop service #{@new_resource}") do stop_service Chef::Log.info("#{@new_resource} stopped") end else Chef::Log.debug("#{@new_resource} already stopped - nothing to do") end load_new_resource_state @new_resource.running(false) end def action_restart converge_by("restart service #{@new_resource}") do restart_service Chef::Log.info("#{@new_resource} restarted") end load_new_resource_state @new_resource.running(true) end def action_reload if @current_resource.running converge_by("reload service #{@new_resource}") do reload_service Chef::Log.info("#{@new_resource} reloaded") end end load_new_resource_state end def enable_service raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :enable" end def disable_service raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :disable" end def start_service raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :start" end def stop_service raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :stop" end def restart_service raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :restart" end def reload_service raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :restart" end protected def default_init_command if @new_resource.init_command @new_resource.init_command elsif self.instance_variable_defined?(:@init_command) @init_command end end def custom_command_for_action?(action) method_name = "#{action}_command".to_sym @new_resource.respond_to?(method_name) && !!@new_resource.send(method_name) end end end end chef-11.8.2/lib/chef/provider/template.rb0000644000004100000410000000352412254362222020211 0ustar www-datawww-data#-- # Author:: Adam Jacob () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008, 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/template_finder' require 'chef/provider/file' require 'chef/deprecation/provider/template' require 'chef/deprecation/warnings' class Chef class Provider class Template < Chef::Provider::File extend Chef::Deprecation::Warnings include Chef::Deprecation::Provider::Template add_deprecation_warnings_for(Chef::Deprecation::Provider::Template.instance_methods) def initialize(new_resource, run_context) @content_class = Chef::Provider::Template::Content super end def load_current_resource @current_resource = Chef::Resource::Template.new(@new_resource.name) super end def define_resource_requirements super requirements.assert(:create, :create_if_missing) do |a| a.assertion { ::File::exists?(content.template_location) } a.failure_message "Template source #{content.template_location} could not be found." a.whyrun "Template source #{content.template_location} does not exist. Assuming it would have been created." a.block_action! end end end end end chef-11.8.2/lib/chef/provider/batch.rb0000644000004100000410000000200112254362222017444 0ustar www-datawww-data# # Author:: Adam Edwards () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/provider/windows_script' class Chef class Provider class Batch < Chef::Provider::WindowsScript def initialize (new_resource, run_context) super(new_resource, run_context, '.bat') end def flags @new_resource.flags.nil? ? '/c' : new_resource.flags + ' /c' end end end end chef-11.8.2/lib/chef/file_access_control/0000755000004100000410000000000012254362222020213 5ustar www-datawww-datachef-11.8.2/lib/chef/file_access_control/windows.rb0000644000004100000410000002342412254362222022237 0ustar www-datawww-data# # Author:: John Keiser () # Author:: Seth Chisamore () # Copyright:: Copyright 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/win32/security' class Chef class FileAccessControl module Windows include Chef::ReservedNames::Win32::API::Security Security = Chef::ReservedNames::Win32::Security ACL = Security::ACL ACE = Security::ACE SID = Security::SID def set_all! set_owner! set_group! set_dacl end def set_all set_owner set_group set_dacl end def define_resource_requirements # windows FAC has no assertions end def requires_changes? should_update_dacl? || should_update_owner? || should_update_group? end def describe_changes # FIXME: describe what these are changing from and to changes = [] changes << "change dacl" if should_update_dacl? changes << "change owner" if should_update_owner? changes << "change group" if should_update_group? changes end private # Compare the actual ACL on a resource with the ACL we want. This # ignores explicit ACLs on the target, and does mask prediction (if you # set GENERIC_WRITE, Windows will flip on a whole bunch of other rights # on the file when you save the ACL) def acls_equal(target_acl, actual_acl) if actual_acl.nil? return target_acl.nil? end actual_acl = actual_acl.select { |ace| !ace.inherited? } # When ACLs apply to children, Windows splits them on the file system into two ACLs: # one specific applying to this container, and one generic applying to children. new_target_acl = [] target_acl.each do |target_ace| if target_ace.flags & INHERIT_ONLY_ACE == 0 self_ace = target_ace.dup self_ace.flags = 0 self_ace.mask = securable_object.predict_rights_mask(target_ace.mask) new_target_acl << self_ace end if target_ace.flags & (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE) != 0 children_ace = target_ace.dup children_ace.flags |= INHERIT_ONLY_ACE new_target_acl << children_ace end end return actual_acl == new_target_acl end def existing_descriptor securable_object.security_descriptor end def get_sid(value) if value.kind_of?(String) SID.from_account(value) elsif value.kind_of?(SID) value else raise "Must specify username, group or SID: #{value}" end end def securable_object @securable_object ||= begin if file.kind_of?(String) so = Chef::ReservedNames::Win32::Security::SecurableObject.new(file.dup) end raise ArgumentError, "'file' must be a valid path or object of type 'Chef::ReservedNames::Win32::Security::SecurableObject'" unless so.kind_of? Chef::ReservedNames::Win32::Security::SecurableObject so end end def should_update_dacl? return true unless ::File.exists?(file) dacl = target_dacl existing_dacl = existing_descriptor.dacl inherits = target_inherits ( ! inherits.nil? && inherits != existing_descriptor.dacl_inherits? ) || ( dacl && !acls_equal(dacl, existing_dacl) ) end def set_dacl! set_dacl end def set_dacl dacl = target_dacl existing_dacl = existing_descriptor.dacl inherits = target_inherits if ! inherits.nil? && inherits != existing_descriptor.dacl_inherits? # We have to set DACL along with inherits. If rights were not # specified, we need to change only inherited ACLs and leave # explicit ACLs alone. if dacl.nil? && !existing_dacl.nil? dacl = ACL.create(existing_dacl.select { |ace| !ace.inherited? }) end securable_object.set_dacl(dacl, inherits) Chef::Log.info("#{log_string} permissions changed to #{dacl} with inherits of #{inherits}") modified elsif dacl && !acls_equal(dacl, existing_dacl) securable_object.dacl = dacl Chef::Log.info("#{log_string} permissions changed to #{dacl}") modified end end def should_update_group? return true unless ::File.exists?(file) (group = target_group) && (group != existing_descriptor.group) end def set_group! if (group = target_group) Chef::Log.info("#{log_string} group changed to #{group}") securable_object.group = group modified end end def set_group if (group = target_group) && (group != existing_descriptor.group) set_group! end end def should_update_owner? return true unless ::File.exists?(file) (owner = target_owner) && (owner != existing_descriptor.owner) end def set_owner! if owner = target_owner Chef::Log.info("#{log_string} owner changed to #{owner}") securable_object.owner = owner modified end end def set_owner if (owner = target_owner) && (owner != existing_descriptor.owner) set_owner! end end def mode_ace(sid, mode) mask = 0 mask |= GENERIC_READ if mode & 4 != 0 mask |= (GENERIC_WRITE | DELETE) if mode & 2 != 0 mask |= GENERIC_EXECUTE if mode & 1 != 0 return [] if mask == 0 [ ACE.access_allowed(sid, mask) ] end def calculate_mask(permissions) mask = 0 [ permissions ].flatten.each do |permission| case permission when :full_control mask |= GENERIC_ALL when :modify mask |= GENERIC_WRITE | GENERIC_READ | GENERIC_EXECUTE | DELETE when :read mask |= GENERIC_READ when :read_execute mask |= GENERIC_READ | GENERIC_EXECUTE when :write mask |= GENERIC_WRITE else # Otherwise, assume it's an integer specifying the actual flags mask |= permission end end mask end def calculate_flags(rights) # Handle inheritance flags flags = 0 # # Configure child inheritence only if the resource is some # type of a directory. # if resource.is_a? Chef::Resource::Directory case rights[:applies_to_children] when :containers_only flags |= CONTAINER_INHERIT_ACE when :objects_only flags |= OBJECT_INHERIT_ACE when true flags |= CONTAINER_INHERIT_ACE flags |= OBJECT_INHERIT_ACE when nil flags |= CONTAINER_INHERIT_ACE flags |= OBJECT_INHERIT_ACE end end if rights[:applies_to_self] == false flags |= INHERIT_ONLY_ACE end if rights[:one_level_deep] flags |= NO_PROPAGATE_INHERIT_ACE end flags end def target_dacl return nil if resource.rights.nil? && resource.deny_rights.nil? && resource.mode.nil? acls = nil if !resource.deny_rights.nil? acls = [] if acls.nil? resource.deny_rights.each do |rights| mask = calculate_mask(rights[:permissions]) [ rights[:principals] ].flatten.each do |principal| sid = get_sid(principal) flags = calculate_flags(rights) acls.push ACE.access_denied(sid, mask, flags) end end end if !resource.rights.nil? acls = [] if acls.nil? resource.rights.each do |rights| mask = calculate_mask(rights[:permissions]) [ rights[:principals] ].flatten.each do |principal| sid = get_sid(principal) flags = calculate_flags(rights) acls.push ACE.access_allowed(sid, mask, flags) end end end if !resource.mode.nil? acls = [] if acls.nil? mode = (resource.mode.respond_to?(:oct) ? resource.mode.oct : resource.mode.to_i) & 0777 owner = target_owner if owner acls += mode_ace(owner, (mode & 0700) >> 6) elsif mode & 0700 != 0 Chef::Log.warn("Mode #{sprintf("%03o", mode)} includes bits for the owner, but owner is not specified") end group = target_group if group acls += mode_ace(group, (mode & 070) >> 3) elsif mode & 070 != 0 Chef::Log.warn("Mode #{sprintf("%03o", mode)} includes bits for the group, but group is not specified") end acls += mode_ace(SID.Everyone, (mode & 07)) end acls.nil? ? nil : Chef::ReservedNames::Win32::Security::ACL.create(acls) end def target_group return nil if resource.group.nil? sid = get_sid(resource.group) end def target_inherits resource.inherits end def target_owner return nil if resource.owner.nil? sid = get_sid(resource.owner) end end end end chef-11.8.2/lib/chef/file_access_control/unix.rb0000644000004100000410000002246212254362222021531 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Daniel DeLeo () # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2008-2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/log' class Chef class FileAccessControl module Unix UINT = (1 << 32) UID_MAX = (1 << 32) - 10 def set_all! set_owner! set_group! set_mode! end def set_all set_owner set_group set_mode end # TODO factor this up def requires_changes? should_update_mode? || should_update_owner? || should_update_group? end def define_resource_requirements uid_from_resource(resource) gid_from_resource(resource) end def describe_changes changes = [] changes << "change mode from '#{mode_to_s(current_mode)}' to '#{mode_to_s(target_mode)}'" if should_update_mode? changes << "change owner from '#{current_resource.owner}' to '#{resource.owner}'" if should_update_owner? changes << "change group from '#{current_resource.group}' to '#{resource.group}'" if should_update_group? changes end def target_uid uid_from_resource(resource) end def current_uid uid_from_resource(current_resource) end def should_update_owner? if target_uid.nil? # the user has not specified a permission on the new resource, so we never manage it with FAC Chef::Log.debug("found target_uid == nil, so no owner was specified on resource, not managing owner") return false elsif current_uid.nil? # the user has specified a permission, and we are creating a file, so always enforce permissions Chef::Log.debug("found current_uid == nil, so we are creating a new file, updating owner") return true elsif target_uid != current_uid # the user has specified a permission, and it does not match the file, so fix the permission Chef::Log.debug("found target_uid != current_uid, updating owner") return true else Chef::Log.debug("found target_uid == current_uid, not updating owner") # the user has specified a permission, but it matches the file, so behave idempotently return false end end def set_owner! unless target_uid.nil? chown(target_uid, nil, file) Chef::Log.info("#{log_string} owner changed to #{target_uid}") modified end end def set_owner set_owner! if should_update_owner? end def target_gid gid_from_resource(resource) end def current_gid gid_from_resource(current_resource) end def gid_from_resource(resource) return nil if resource == nil or resource.group.nil? if resource.group.kind_of?(String) diminished_radix_complement( Etc.getgrnam(resource.group).gid ) elsif resource.group.kind_of?(Integer) resource.group else Chef::Log.error("The `group` parameter of the #@resource resource is set to an invalid value (#{resource.owner.inspect})") raise ArgumentError, "cannot resolve #{resource.group.inspect} to gid, group must be a string or integer" end rescue ArgumentError provider.requirements.assert(:create, :create_if_missing, :touch) do |a| a.assertion { false } a.failure_message(Chef::Exceptions::GroupIDNotFound, "cannot determine group id for '#{resource.group}', does the group exist on this system?") a.whyrun("Assuming group #{resource.group} would have been created") end return nil end def should_update_group? if target_gid.nil? # the user has not specified a permission on the new resource, so we never manage it with FAC Chef::Log.debug("found target_gid == nil, so no group was specified on resource, not managing group") return false elsif current_gid.nil? # the user has specified a permission, and we are creating a file, so always enforce permissions Chef::Log.debug("found current_gid == nil, so we are creating a new file, updating group") return true elsif target_gid != current_gid # the user has specified a permission, and it does not match the file, so fix the permission Chef::Log.debug("found target_gid != current_gid, updating group") return true else Chef::Log.debug("found target_gid == current_gid, not updating group") # the user has specified a permission, but it matches the file, so behave idempotently return false end end def set_group! unless target_gid.nil? chown(nil, target_gid, file) Chef::Log.info("#{log_string} group changed to #{target_gid}") modified end end def set_group set_group! if should_update_group? end def mode_from_resource(res) return nil if res == nil or res.mode.nil? (res.mode.respond_to?(:oct) ? res.mode.oct : res.mode.to_i) & 007777 end def target_mode mode_from_resource(resource) end def mode_to_s(mode) mode.nil? ? "" : "0#{mode.to_s(8)}" end def current_mode mode_from_resource(current_resource) end def should_update_mode? if target_mode.nil? # the user has not specified a permission on the new resource, so we never manage it with FAC Chef::Log.debug("found target_mode == nil, so no mode was specified on resource, not managing mode") return false elsif current_mode.nil? # the user has specified a permission, and we are creating a file, so always enforce permissions Chef::Log.debug("found current_mode == nil, so we are creating a new file, updating mode") return true elsif target_mode != current_mode # the user has specified a permission, and it does not match the file, so fix the permission Chef::Log.debug("found target_mode != current_mode, updating mode") return true else Chef::Log.debug("found target_mode == current_mode, not updating mode") # the user has specified a permission, but it matches the file, so behave idempotently return false end end def set_mode! unless target_mode.nil? chmod(target_mode, file) Chef::Log.info("#{log_string} mode changed to #{target_mode.to_s(8)}") modified end end def set_mode set_mode! if should_update_mode? end def stat if manage_symlink_attrs? @stat ||= File.lstat(file) else @stat ||= File.stat(file) end end def manage_symlink_attrs? @provider.manage_symlink_access? end private def chmod(mode, file) if manage_symlink_attrs? begin File.lchmod(mode, file) rescue NotImplementedError Chef::Log.warn("#{file} mode not changed: File.lchmod is unimplemented on this OS and Ruby version") end else File.chmod(mode, file) end end def chown(uid, gid, file) if manage_symlink_attrs? File.lchown(uid, gid, file) else File.chown(uid, gid, file) end end # Workaround the fact that Ruby's Etc module doesn't believe in negative # uids, so negative uids show up as the diminished radix complement of # a uint. For example, a uid of -2 is reported as 4294967294 def diminished_radix_complement(int) if int > UID_MAX int - UINT else int end end def uid_from_resource(resource) return nil if resource == nil or resource.owner.nil? if resource.owner.kind_of?(String) diminished_radix_complement( Etc.getpwnam(resource.owner).uid ) elsif resource.owner.kind_of?(Integer) resource.owner else Chef::Log.error("The `owner` parameter of the #@resource resource is set to an invalid value (#{resource.owner.inspect})") raise ArgumentError, "cannot resolve #{resource.owner.inspect} to uid, owner must be a string or integer" end rescue ArgumentError provider.requirements.assert(:create, :create_if_missing, :touch) do |a| a.assertion { false } a.failure_message(Chef::Exceptions::UserIDNotFound, "cannot determine user id for '#{resource.owner}', does the user exist on this system?") a.whyrun("Assuming user #{resource.owner} would have been created") end return nil end end end end chef-11.8.2/lib/chef/version.rb0000644000004100000410000000152612254362222016231 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010-2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. class Chef CHEF_ROOT = File.dirname(File.expand_path(File.dirname(__FILE__))) VERSION = '11.8.2' end # NOTE: the Chef::Version class is defined in version_class.rb chef-11.8.2/lib/chef/cookbook_uploader.rb0000644000004100000410000001411712254362222020245 0ustar www-datawww-data require 'set' require 'rest_client' require 'chef/exceptions' require 'chef/knife/cookbook_metadata' require 'chef/digester' require 'chef/cookbook_version' require 'chef/cookbook/syntax_check' require 'chef/cookbook/file_system_file_vendor' require 'chef/sandbox' class Chef class CookbookUploader def self.work_queue @work_queue ||= Queue.new end def self.setup_worker_threads @worker_threads ||= begin work_queue (1...10).map do Thread.new do loop do work_queue.pop.call end end end end end attr_reader :cookbooks attr_reader :path attr_reader :opts attr_reader :rest # Creates a new CookbookUploader. # ===Arguments: # * cookbooks::: A Chef::CookbookVersion or array of them describing the # cookbook(s) to be uploaded # * path::: A String or Array of Strings representing the base paths to the # cookbook repositories. # * opts::: (optional) An options Hash # ===Options: # * :force indicates that the uploader should set the force option when # uploading the cookbook. This allows frozen CookbookVersion # documents on the server to be overwritten (otherwise a 409 is # returned by the server) # * :rest A Chef::REST object that you have configured the way you like it. # If you don't provide this, one will be created using the values # in Chef::Config. def initialize(cookbooks, path, opts={}) @path, @opts = path, opts @cookbooks = Array(cookbooks) @rest = opts[:rest] || Chef::REST.new(Chef::Config[:chef_server_url]) end def upload_cookbooks Thread.abort_on_exception = true # Syntax Check validate_cookbooks # generate checksums of cookbook files and create a sandbox checksum_files = {} cookbooks.each do |cb| Chef::Log.info("Saving #{cb.name}") checksum_files.merge!(cb.checksums) end checksums = checksum_files.inject({}){|memo,elt| memo[elt.first]=nil ; memo} new_sandbox = rest.post_rest("sandboxes", { :checksums => checksums }) Chef::Log.info("Uploading files") self.class.setup_worker_threads checksums_to_upload = Set.new # upload the new checksums and commit the sandbox new_sandbox['checksums'].each do |checksum, info| if info['needs_upload'] == true checksums_to_upload << checksum Chef::Log.info("Uploading #{checksum_files[checksum]} (checksum hex = #{checksum}) to #{info['url']}") self.class.work_queue << uploader_function_for(checksum_files[checksum], checksum, info['url'], checksums_to_upload) else Chef::Log.debug("#{checksum_files[checksum]} has not changed") end end until checksums_to_upload.empty? sleep 0.1 end sandbox_url = new_sandbox['uri'] Chef::Log.debug("Committing sandbox") # Retry if S3 is claims a checksum doesn't exist (the eventual # in eventual consistency) retries = 0 begin rest.put_rest(sandbox_url, {:is_completed => true}) rescue Net::HTTPServerException => e if e.message =~ /^400/ && (retries += 1) <= 5 sleep 2 retry else raise end end # files are uploaded, so save the manifest cookbooks.each do |cb| save_url = opts[:force] ? cb.force_save_url : cb.save_url begin rest.put_rest(save_url, cb) rescue Net::HTTPServerException => e case e.response.code when "409" raise Chef::Exceptions::CookbookFrozen, "Version #{cb.version} of cookbook #{cb.name} is frozen. Use --force to override." else raise end end end Chef::Log.info("Upload complete!") end def worker_thread(work_queue) end def uploader_function_for(file, checksum, url, checksums_to_upload) lambda do # Checksum is the hexadecimal representation of the md5, # but we need the base64 encoding for the content-md5 # header checksum64 = Base64.encode64([checksum].pack("H*")).strip timestamp = Time.now.utc.iso8601 file_contents = File.open(file, "rb") {|f| f.read} # TODO - 5/28/2010, cw: make signing and sending the request streaming headers = { 'content-type' => 'application/x-binary', 'content-md5' => checksum64, :accept => 'application/json' } if rest.signing_key sign_obj = Mixlib::Authentication::SignedHeaderAuth.signing_object( :http_method => :put, :path => URI.parse(url).path, :body => file_contents, :timestamp => timestamp, :user_id => rest.client_name ) headers.merge!(sign_obj.sign(OpenSSL::PKey::RSA.new(rest.signing_key))) end begin RestClient::Resource.new(url, :headers=>headers, :timeout=>1800, :open_timeout=>1800).put(file_contents) checksums_to_upload.delete(checksum) rescue RestClient::Exception => e Chef::Knife.ui.error("Failed to upload #@cookbook : #{e.message}\n#{e.response.body}") raise end end end def validate_cookbooks cookbooks.each do |cb| syntax_checker = Chef::Cookbook::SyntaxCheck.for_cookbook(cb.name, @user_cookbook_path) Chef::Log.info("Validating ruby files") exit(1) unless syntax_checker.validate_ruby_files Chef::Log.info("Validating templates") exit(1) unless syntax_checker.validate_templates Chef::Log.info("Syntax OK") true end end end end chef-11.8.2/lib/chef/log.rb0000644000004100000410000000213212254362222015317 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: AJ Christensen (<@aj@opscode.com>) # Author:: Christopher Brown () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'logger' require 'chef/monologger' require 'mixlib/log' class Chef class Log extend Mixlib::Log # Force initialization of the primary log device (@logger) init(MonoLogger.new(STDOUT)) class Formatter def self.show_time=(*args) Mixlib::Log::Formatter.show_time = *args end end end end chef-11.8.2/lib/chef/formatters/0000755000004100000410000000000012254362222016401 5ustar www-datawww-datachef-11.8.2/lib/chef/formatters/doc.rb0000644000004100000410000001657612254362222017512 0ustar www-datawww-datarequire 'chef/formatters/base' require 'chef/config' class Chef module Formatters #-- # TODO: not sold on the name, but the output is similar to what rspec calls # "specdoc" class Doc < Formatters::Base cli_name(:doc) def initialize(out, err) super @updated_resources = 0 end def run_start(version) puts "Starting Chef Client, version #{version}" end def run_completed(node) if Chef::Config[:why_run] puts "Chef Client finished, #{@updated_resources} resources would have been updated" else puts "Chef Client finished, #{@updated_resources} resources updated" end end def run_failed(exception) if Chef::Config[:why_run] puts "Chef Client failed. #{@updated_resources} resources would have been updated" else puts "Chef Client failed. #{@updated_resources} resources updated" end end # Called right after ohai runs. def ohai_completed(node) end # Already have a client key, assuming this node has registered. def skipping_registration(node_name, config) end # About to attempt to register as +node_name+ def registration_start(node_name, config) puts "Creating a new client identity for #{node_name} using the validator key." end def registration_completed end def node_load_start(node_name, config) end # Failed to load node data from the server def node_load_failed(node_name, exception, config) super end # Default and override attrs from roles have been computed, but not yet applied. # Normal attrs from JSON have been added to the node. def node_load_completed(node, expanded_run_list, config) end # Called before the cookbook collection is fetched from the server. def cookbook_resolution_start(expanded_run_list) puts "resolving cookbooks for run list: #{expanded_run_list.inspect}" end # Called when there is an error getting the cookbook collection from the # server. def cookbook_resolution_failed(expanded_run_list, exception) super end # Called when the cookbook collection is returned from the server. def cookbook_resolution_complete(cookbook_collection) end # Called before unneeded cookbooks are removed def cookbook_clean_start end # Called after the file at +path+ is removed. It may be removed if the # cookbook containing it was removed from the run list, or if the file was # removed from the cookbook. def removed_cookbook_file(path) end # Called when cookbook cleaning is finished. def cookbook_clean_complete end # Called before cookbook sync starts def cookbook_sync_start(cookbook_count) puts "Synchronizing Cookbooks:" end # Called when cookbook +cookbook_name+ has been sync'd def synchronized_cookbook(cookbook_name) puts " - #{cookbook_name}" end # Called when an individual file in a cookbook has been updated def updated_cookbook_file(cookbook_name, path) end # Called after all cookbooks have been sync'd. def cookbook_sync_complete end # Called when cookbook loading starts. def library_load_start(file_count) puts "Compiling Cookbooks..." end # Called after a file in a cookbook is loaded. def file_loaded(path) end # Called when recipes have been loaded. def recipe_load_complete end # Called before convergence starts def converge_start(run_context) puts "Converging #{run_context.resource_collection.all_resources.size} resources" end # Called when the converge phase is finished. def converge_complete end # Called before action is executed on a resource. def resource_action_start(resource, action, notification_type=nil, notifier=nil) if resource.cookbook_name && resource.recipe_name resource_recipe = "#{resource.cookbook_name}::#{resource.recipe_name}" else resource_recipe = "" end if resource_recipe != @current_recipe puts "Recipe: #{resource_recipe}" @current_recipe = resource_recipe end # TODO: info about notifies print " * #{resource} action #{action}" end # Called when a resource fails, but will retry. def resource_failed_retriable(resource, action, retry_count, exception) end # Called when a resource fails and will not be retried. def resource_failed(resource, action, exception) super end # Called when a resource action has been skipped b/c of a conditional def resource_skipped(resource, action, conditional) # TODO: more info about conditional puts " (skipped due to #{conditional.short_description})" end # Called after #load_current_resource has run. def resource_current_state_loaded(resource, action, current_resource) end # Called when a resource has no converge actions, e.g., it was already correct. def resource_up_to_date(resource, action) puts " (up to date)" end def resource_bypassed(resource, action, provider) puts " (Skipped: whyrun not supported by provider #{provider.class.name})" end def output_record(line) end # Called when a change has been made to a resource. May be called multiple # times per resource, e.g., a file may have its content updated, and then # its permissions updated. def resource_update_applied(resource, action, update) prefix = Chef::Config[:why_run] ? "Would " : "" Array(update).each do |line| next if line.nil? output_record line if line.kind_of? String @output.color "\n - #{prefix}#{line}", :green elsif line.kind_of? Array # Expanded output - delta # @todo should we have a resource_update_delta callback? line.each do |detail| @output.color "\n #{detail}", :white end end end end # Called after a resource has been completely converged. def resource_updated(resource, action) @updated_resources += 1 puts "\n" end # Called when resource current state load is skipped due to the provider # not supporting whyrun mode. def resource_current_state_load_bypassed(resource, action, current_resource) @output.color("\n * Whyrun not supported for #{resource}, bypassing load.", :yellow) end # Called when a provider makes an assumption after a failed assertion # in whyrun mode, in order to allow execution to continue def whyrun_assumption(action, resource, message) return unless message [ message ].flatten.each do |line| @output.color("\n * #{line}", :yellow) end end # Called when an assertion declared by a provider fails def provider_requirement_failed(action, resource, exception, message) return unless message color = Chef::Config[:why_run] ? :yellow : :red [ message ].flatten.each do |line| @output.color("\n * #{line}", color) end end end end end chef-11.8.2/lib/chef/formatters/error_inspectors.rb0000644000004100000410000000141212254362222022326 0ustar www-datawww-datarequire 'chef/formatters/error_inspectors/node_load_error_inspector' require "chef/formatters/error_inspectors/registration_error_inspector" require 'chef/formatters/error_inspectors/compile_error_inspector' require 'chef/formatters/error_inspectors/resource_failure_inspector' require 'chef/formatters/error_inspectors/run_list_expansion_error_inspector' require 'chef/formatters/error_inspectors/cookbook_resolve_error_inspector' require "chef/formatters/error_inspectors/cookbook_sync_error_inspector" class Chef module Formatters # == ErrorInspectors # Error inspectors wrap exceptions and contextual information. They # generate diagnostic messages about possible causes of the error for user # consumption. module ErrorInspectors end end end chef-11.8.2/lib/chef/formatters/minimal.rb0000644000004100000410000001564712254362222020371 0ustar www-datawww-datarequire 'chef/formatters/base' class Chef module Formatters # == Formatters::Minimal # Shows the progress of the chef run by printing single characters, and # displays a summary of updates at the conclusion of the run. For events # that don't have meaningful status information (loading a file, syncing a # cookbook) a dot is printed. For resources, a dot, 'S' or 'U' is printed # if the resource is up to date, skipped by not_if/only_if, or updated, # respectively. class Minimal < Formatters::Base cli_name(:minimal) cli_name(:min) attr_reader :updated_resources attr_reader :updates_by_resource def initialize(out, err) super @updated_resources = [] @updates_by_resource = Hash.new {|h, k| h[k] = []} end # Called at the very start of a Chef Run def run_start(version) puts "Starting Chef Client, version #{version}" end # Called at the end of the Chef run. def run_completed(node) puts "chef client finished, #{@updated_resources.size} resources updated" end # called at the end of a failed run def run_failed(exception) puts "chef client failed. #{@updated_resources.size} resources updated" end # Called right after ohai runs. def ohai_completed(node) end # Already have a client key, assuming this node has registered. def skipping_registration(node_name, config) end # About to attempt to register as +node_name+ def registration_start(node_name, config) end def registration_completed end # Failed to register this client with the server. def registration_failed(node_name, exception, config) super end def node_load_start(node_name, config) end # Failed to load node data from the server def node_load_failed(node_name, exception, config) end # Default and override attrs from roles have been computed, but not yet applied. # Normal attrs from JSON have been added to the node. def node_load_completed(node, expanded_run_list, config) end # Called before the cookbook collection is fetched from the server. def cookbook_resolution_start(expanded_run_list) puts "resolving cookbooks for run list: #{expanded_run_list.inspect}" end # Called when there is an error getting the cookbook collection from the # server. def cookbook_resolution_failed(expanded_run_list, exception) end # Called when the cookbook collection is returned from the server. def cookbook_resolution_complete(cookbook_collection) end # Called before unneeded cookbooks are removed #-- # TODO: Should be called in CookbookVersion.sync_cookbooks def cookbook_clean_start end # Called after the file at +path+ is removed. It may be removed if the # cookbook containing it was removed from the run list, or if the file was # removed from the cookbook. def removed_cookbook_file(path) end # Called when cookbook cleaning is finished. def cookbook_clean_complete end # Called before cookbook sync starts def cookbook_sync_start(cookbook_count) puts "Synchronizing cookbooks" end # Called when cookbook +cookbook_name+ has been sync'd def synchronized_cookbook(cookbook_name) print "." end # Called when an individual file in a cookbook has been updated def updated_cookbook_file(cookbook_name, path) end # Called after all cookbooks have been sync'd. def cookbook_sync_complete puts "done." end # Called when cookbook loading starts. def library_load_start(file_count) puts "Compiling cookbooks" end # Called after a file in a cookbook is loaded. def file_loaded(path) print '.' end def file_load_failed(path, exception) super end # Called when recipes have been loaded. def recipe_load_complete puts "done." end # Called before convergence starts def converge_start(run_context) puts "Converging #{run_context.resource_collection.all_resources.size} resources" end # Called when the converge phase is finished. def converge_complete puts "\n" puts "System converged." if updated_resources.empty? puts "no resources updated" else puts "\n" puts "resources updated this run:" updated_resources.each do |resource| puts "* #{resource.to_s}" updates_by_resource[resource.name].flatten.each do |update| puts " - #{update}" end puts "\n" end end end # Called before action is executed on a resource. def resource_action_start(resource, action, notification_type=nil, notifier=nil) end # Called when a resource fails, but will retry. def resource_failed_retriable(resource, action, retry_count, exception) end # Called when a resource fails and will not be retried. def resource_failed(resource, action, exception) end # Called when a resource action has been skipped b/c of a conditional def resource_skipped(resource, action, conditional) print "S" end # Called after #load_current_resource has run. def resource_current_state_loaded(resource, action, current_resource) end # Called when a resource has no converge actions, e.g., it was already correct. def resource_up_to_date(resource, action) print "." end ## TODO: callback for assertion failures ## TODO: callback for assertion fallback in why run # Called when a change has been made to a resource. May be called multiple # times per resource, e.g., a file may have its content updated, and then # its permissions updated. def resource_update_applied(resource, action, update) @updates_by_resource[resource.name] << Array(update)[0] end # Called after a resource has been completely converged. def resource_updated(resource, action) updated_resources << resource print "U" end # Called before handlers run def handlers_start(handler_count) end # Called after an individual handler has run def handler_executed(handler) end # Called after all handlers have executed def handlers_completed end # An uncategorized message. This supports the case that a user needs to # pass output that doesn't fit into one of the callbacks above. Note that # there's no semantic information about the content or importance of the # message. That means that if you're using this too often, you should add a # callback for it. def msg(message) end end end end chef-11.8.2/lib/chef/formatters/error_descriptor.rb0000644000004100000410000000312712254362222022320 0ustar www-datawww-data# # Author:: Tyler Cloke () # # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef module Formatters # == Formatters::ErrorDescription # Class for displaying errors on STDOUT. class ErrorDescription attr_reader :sections def initialize(title) @title = title @sections = [] end def section(heading, text) @sections << {heading => text} end def display(out) out.puts "=" * 80 out.puts @title, :red out.puts "=" * 80 out.puts "\n" sections.each do |section| section.each do |heading, text| display_section(heading, text, out) end end end def for_json() { 'title' => @title, 'sections' => @sections } end private def display_section(heading, text, out) out.puts heading out.puts "-" * heading.size out.puts text out.puts "\n" end end end end chef-11.8.2/lib/chef/formatters/error_mapper.rb0000644000004100000410000000705512254362222021432 0ustar www-datawww-data#-- # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef module Formatters # == Formatters::ErrorMapper # Collection of methods for creating and returning # Formatters::ErrorDescription objects based on node, # exception, and configuration information. module ErrorMapper # Failed to register this client with the server. def self.registration_failed(node_name, exception, config) error_inspector = ErrorInspectors::RegistrationErrorInspector.new(node_name, exception, config) headline = "Chef encountered an error attempting to create the client \"#{node_name}\"" description = ErrorDescription.new(headline) error_inspector.add_explanation(description) return description end def self.node_load_failed(node_name, exception, config) error_inspector = ErrorInspectors::NodeLoadErrorInspector.new(node_name, exception, config) headline = "Chef encountered an error attempting to load the node data for \"#{node_name}\"" description = ErrorDescription.new(headline) error_inspector.add_explanation(description) return description end def self.run_list_expand_failed(node, exception) error_inspector = ErrorInspectors::RunListExpansionErrorInspector.new(node, exception) headline = "Error expanding the run_list:" description = ErrorDescription.new(headline) error_inspector.add_explanation(description) return description end def self.cookbook_resolution_failed(expanded_run_list, exception) error_inspector = ErrorInspectors::CookbookResolveErrorInspector.new(expanded_run_list, exception) headline = "Error Resolving Cookbooks for Run List:" description = ErrorDescription.new(headline) error_inspector.add_explanation(description) return description end def self.cookbook_sync_failed(cookbooks, exception) error_inspector = ErrorInspectors::CookbookSyncErrorInspector.new(cookbooks, exception) headline = "Error Syncing Cookbooks:" description = ErrorDescription.new(headline) error_inspector.add_explanation(description) return description end def self.resource_failed(resource, action, exception) error_inspector = ErrorInspectors::ResourceFailureInspector.new(resource, action, exception) headline = "Error executing action `#{action}` on resource '#{resource}'" description = ErrorDescription.new(headline) error_inspector.add_explanation(description) return description end def self.file_load_failed(path, exception) error_inspector = ErrorInspectors::CompileErrorInspector.new(path, exception) headline = "Recipe Compile Error" + ( path ? " in #{path}" : "" ) description = ErrorDescription.new(headline) error_inspector.add_explanation(description) description end end end end chef-11.8.2/lib/chef/formatters/base.rb0000644000004100000410000001525412254362222017647 0ustar www-datawww-data# # Author:: Tyler Cloke () # # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/event_dispatch/base' require 'chef/formatters/error_inspectors' require 'chef/formatters/error_descriptor' require 'chef/formatters/error_mapper' class Chef # == Chef::Formatters # Formatters handle printing output about the progress/status of a chef # client run to the user's screen. module Formatters class UnknownFormatter < StandardError; end def self.formatters_by_name @formatters_by_name ||= {} end def self.register(name, formatter) formatters_by_name[name.to_s] = formatter end def self.by_name(name) formatters_by_name[name] end def self.available_formatters formatters_by_name.keys end #-- # TODO: is it too clever to be defining new() on a module like this? def self.new(name, out, err) formatter_class = by_name(name.to_s) or raise UnknownFormatter, "No output formatter found for #{name} (available: #{available_formatters.join(', ')})" formatter_class.new(out, err) end # == Outputter # Handles basic printing tasks like colorizing. # -- # TODO: Duplicates functionality from knife, upfactor. class Outputter attr_reader :out attr_reader :err def initialize(out, err) @out, @err = out, err end def highline @highline ||= begin require 'highline' HighLine.new end end def color(string, *colors) if Chef::Config[:color] @out.print highline.color(string, *colors) else @out.print string end end alias :print :color def puts(string, *colors) if Chef::Config[:color] @out.puts highline.color(string, *colors) else @out.puts string end end end # == Formatters::Base # Base class that all formatters should inherit from. class Base < EventDispatch::Base include ErrorMapper def self.cli_name(name) Chef::Formatters.register(name, self) end attr_reader :out attr_reader :err attr_reader :output def initialize(out, err) @output = Outputter.new(out, err) end def puts(*args) @output.puts(*args) end def print(*args) @output.print(*args) end # Input: a Formatters::ErrorDescription object. # Outputs error to SDOUT. def display_error(description) puts("") description.display(output) end def registration_failed(node_name, exception, config) #A Formatters::ErrorDescription object description = ErrorMapper.registration_failed(node_name, exception, config) display_error(description) end def node_load_failed(node_name, exception, config) description = ErrorMapper.node_load_failed(node_name, exception, config) display_error(description) end def run_list_expand_failed(node, exception) description = ErrorMapper.run_list_expand_failed(node, exception) display_error(description) end def cookbook_resolution_failed(expanded_run_list, exception) description = ErrorMapper.cookbook_resolution_failed(expanded_run_list, exception) display_error(description) end def cookbook_sync_failed(cookbooks, exception) description = ErrorMapper.cookbook_sync_failed(cookbooks, exception) display_error(description) end def resource_failed(resource, action, exception) description = ErrorMapper.resource_failed(resource, action, exception) display_error(description) end # Generic callback for any attribute/library/lwrp/recipe file in a # cookbook getting loaded. The per-filetype callbacks for file load are # overriden so that they call this instead. This means that a subclass of # Formatters::Base can implement #file_loaded to do the same thing for # every kind of file that Chef loads from a recipe instead of # implementing all the per-filetype callbacks. def file_loaded(path) end # Generic callback for any attribute/library/lwrp/recipe file throwing an # exception when loaded. Default behavior is to use CompileErrorInspector # to print contextual info about the failure. def file_load_failed(path, exception) description = ErrorMapper.file_load_failed(path, exception) display_error(description) end def recipe_not_found(exception) description = ErrorMapper.file_load_failed(nil, exception) display_error(description) end # Delegates to #file_loaded def library_file_loaded(path) file_loaded(path) end # Delegates to #file_load_failed def library_file_load_failed(path, exception) file_load_failed(path, exception) end # Delegates to #file_loaded def lwrp_file_loaded(path) file_loaded(path) end # Delegates to #file_load_failed def lwrp_file_load_failed(path, exception) file_load_failed(path, exception) end # Delegates to #file_loaded def attribute_file_loaded(path) file_loaded(path) end # Delegates to #file_load_failed def attribute_file_load_failed(path, exception) file_load_failed(path, exception) end # Delegates to #file_loaded def definition_file_loaded(path) file_loaded(path) end # Delegates to #file_load_failed def definition_file_load_failed(path, exception) file_load_failed(path, exception) end # Delegates to #file_loaded def recipe_file_loaded(path) file_loaded(path) end # Delegates to #file_load_failed def recipe_file_load_failed(path, exception) file_load_failed(path, exception) end end # == NullFormatter # Formatter that doesn't actually produce any ouput. You can use this to # disable the use of output formatters. class NullFormatter < Base cli_name(:null) end end end chef-11.8.2/lib/chef/formatters/error_inspectors/0000755000004100000410000000000012254362222022003 5ustar www-datawww-datachef-11.8.2/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb0000644000004100000410000000764612254362222027771 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef module Formatters module ErrorInspectors class ResourceFailureInspector attr_reader :resource attr_reader :action attr_reader :exception def initialize(resource, action, exception) @resource = resource @action = action @exception = exception end def add_explanation(error_description) error_description.section(exception.class.name, exception.message) unless filtered_bt.empty? error_description.section("Cookbook Trace:", filtered_bt.join("\n")) end unless dynamic_resource? error_description.section("Resource Declaration:", recipe_snippet) end error_description.section("Compiled Resource:", "#{resource.to_text}") # Template errors get wrapped in an exception class that can show the relevant template code, # so add them to the error output. if exception.respond_to?(:source_listing) error_description.section("Template Context:", "#{exception.source_location}\n#{exception.source_listing}") end if Chef::Platform.windows? require 'chef/win32/security' if !Chef::ReservedNames::Win32::Security.has_admin_privileges? error_description.section("Missing Windows Admin Privileges", "chef-client doesn't have administrator privileges. This can be a possible reason for the resource failure.") end end end def recipe_snippet return nil if dynamic_resource? @snippet ||= begin if file = resource.source_line[/^(([\w]:)?[^:]+):([\d]+)/,1] and line = resource.source_line[/^#{file}:([\d]+)/,1].to_i return nil unless ::File.exists?(file) lines = IO.readlines(file) relevant_lines = ["# In #{file}\n\n"] current_line = line - 1 current_line = 0 if current_line < 0 nesting = 0 loop do # low rent parser. try to gracefully handle nested blocks in resources nesting += 1 if lines[current_line] =~ /[\s]+do[\s]*/ nesting -= 1 if lines[current_line] =~ /end[\s]*$/ relevant_lines << format_line(current_line, lines[current_line]) break if lines[current_line + 1].nil? break if current_line >= (line + 50) break if nesting <= 0 current_line += 1 end relevant_lines << format_line(current_line + 1, lines[current_line + 1]) if lines[current_line + 1] relevant_lines.join("") end end end def dynamic_resource? !resource.source_line end def filtered_bt filters = Array(Chef::Config.cookbook_path).map {|p| /^#{Regexp.escape(p)}/ } exception.backtrace.select {|line| filters.any? {|filter| line =~ filter }} end private def format_line(line_nr, line) # Print line number as 1-indexed not zero line_nr_string = (line_nr + 1).to_s.rjust(3) + ": " line_nr_string + line end end end end end chef-11.8.2/lib/chef/formatters/error_inspectors/registration_error_inspector.rb0000644000004100000410000001205612254362222030345 0ustar www-datawww-dataclass Chef module Formatters module ErrorInspectors # == RegistrationErrorInspector # Wraps exceptions that occur during the client registration process and # suggests possible causes. #-- # TODO: Lots of duplication with the node_load_error_inspector, just # slightly tweaked to talk about validation keys instead of other keys. class RegistrationErrorInspector attr_reader :exception attr_reader :node_name attr_reader :config def initialize(node_name, exception, config) @node_name = node_name @exception = exception @config = config end def add_explanation(error_description) case exception when Net::HTTPServerException, Net::HTTPFatalError humanize_http_exception(error_description) when Errno::ECONNREFUSED, Timeout::Error, Errno::ETIMEDOUT, SocketError error_description.section("Network Error:",<<-E) There was a network error connecting to the Chef Server: #{exception.message} E error_description.section("Relevant Config Settings:",<<-E) chef_server_url "#{server_url}" If your chef_server_url is correct, your network could be down. E when Chef::Exceptions::PrivateKeyMissing error_description.section("Private Key Not Found:",<<-E) Your private key could not be loaded. If the key file exists, ensure that it is readable by chef-client. E error_description.section("Relevant Config Settings:",<<-E) validation_key "#{api_key}" E when Chef::Exceptions::InvalidRedirect error_description.section("Invalid Redirect:",<<-E) Change your server location in client.rb to the server's FQDN to avoid unwanted redirections. E else "#{exception.class.name}: #{exception.message}" end end def humanize_http_exception(error_description) response = exception.response case response when Net::HTTPUnauthorized if clock_skew? error_description.section("Authentication Error:",<<-E) Failed to authenticate to the chef server (http 401). The request failed because your clock has drifted by more than 15 minutes. Syncing your clock to an NTP Time source should resolve the issue. E else error_description.section("Authentication Error:",<<-E) Failed to authenticate to the chef server (http 401). E error_description.section("Server Response:", format_rest_error) error_description.section("Relevant Config Settings:",<<-E) chef_server_url "#{server_url}" validation_client_name "#{username}" validation_key "#{api_key}" If these settings are correct, your validation_key may be invalid. E end when Net::HTTPForbidden error_description.section("Authorization Error:",<<-E) Your validation client is not authorized to create the client for this node (HTTP 403). E error_description.section("Possible Causes:",<<-E) * There may already be a client named "#{config[:node_name]}" * Your validation client (#{username}) may have misconfigured authorization permissions. E when Net::HTTPBadRequest error_description.section("Invalid Request Data:",<<-E) The data in your request was invalid (HTTP 400). E error_description.section("Server Response:",format_rest_error) when Net::HTTPNotFound error_description.section("Resource Not Found:",<<-E) The server returned a HTTP 404. This usually indicates that your chef_server_url is incorrect. E error_description.section("Relevant Config Settings:",<<-E) chef_server_url "#{server_url}" E when Net::HTTPInternalServerError error_description.section("Unknown Server Error:",<<-E) The server had a fatal error attempting to load the node data. E error_description.section("Server Response:", format_rest_error) when Net::HTTPBadGateway, Net::HTTPServiceUnavailable error_description.section("Server Unavailable","The Chef Server is temporarily unavailable") error_description.section("Server Response:", format_rest_error) else error_description.section("Unexpected API Request Failure:", format_rest_error) end end def username #config[:node_name] config[:validation_client_name] end def api_key config[:validation_key] #config[:client_key] end def server_url config[:chef_server_url] end def clock_skew? exception.response.body =~ /synchronize the clock/i end # Parses JSON from the error response sent by Chef Server and returns the # error message #-- # TODO: this code belongs in Chef::REST def format_rest_error Array(Chef::JSONCompat.from_json(exception.response.body)["error"]).join('; ') rescue Exception exception.response.body end end end end end chef-11.8.2/lib/chef/formatters/error_inspectors/compile_error_inspector.rb0000644000004100000410000000657512254362222027274 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef module Formatters module ErrorInspectors # == CompileErrorInspector # Wraps exceptions that occur during the compile phase of a Chef run and # tries to find the code responsible for the error. class CompileErrorInspector attr_reader :path attr_reader :exception def initialize(path, exception) @path, @exception = path, exception end def add_explanation(error_description) case exception when Chef::Exceptions::RecipeNotFound error_description.section(exception.class.name, exception.message) else error_description.section(exception.class.name, exception.message) traceback = filtered_bt.map {|line| " #{line}"}.join("\n") error_description.section("Cookbook Trace:", traceback) error_description.section("Relevant File Content:", context) end end def context context_lines = [] context_lines << "#{culprit_file}:\n\n" Range.new(display_lower_bound, display_upper_bound).each do |i| line_nr = (i + 1).to_s.rjust(3) indicator = (i + 1) == culprit_line ? ">> " : ": " context_lines << "#{line_nr}#{indicator}#{file_lines[i]}" end context_lines.join("") end def display_lower_bound lower = (culprit_line - 8) lower = 0 if lower < 0 lower end def display_upper_bound upper = (culprit_line + 8) upper = file_lines.size if upper > file_lines.size upper end def file_lines @file_lines ||= IO.readlines(culprit_file) end def culprit_backtrace_entry @culprit_backtrace_entry ||= begin bt_entry = filtered_bt.first Chef::Log.debug("backtrace entry for compile error: '#{bt_entry}'") bt_entry end end def culprit_line @culprit_line ||= begin line_number = culprit_backtrace_entry[/^(?:.\:)?[^:]+:([\d]+)/,1].to_i Chef::Log.debug("Line number of compile error: '#{line_number}'") line_number end end def culprit_file @culprit_file ||= culprit_backtrace_entry[/^((?:.\:)?[^:]+):([\d]+)/,1] end def filtered_bt filters = Array(Chef::Config.cookbook_path).map {|p| /^#{Regexp.escape(p)}/ } r = exception.backtrace.select {|line| filters.any? {|filter| line =~ filter }} Chef::Log.debug("filtered backtrace of compile error: #{r.join(",")}") return r.count > 0 ? r : exception.backtrace end end end end end chef-11.8.2/lib/chef/formatters/error_inspectors/node_load_error_inspector.rb0000644000004100000410000001015312254362222027553 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/formatters/error_inspectors/api_error_formatting' class Chef module Formatters module ErrorInspectors # == APIErrorInspector # Wraps exceptions caused by API calls to the server. class NodeLoadErrorInspector include APIErrorFormatting attr_reader :exception attr_reader :node_name attr_reader :config def initialize(node_name, exception, config) @node_name = node_name @exception = exception @config = config end def add_explanation(error_description) case exception when Net::HTTPServerException, Net::HTTPFatalError humanize_http_exception(error_description) when *NETWORK_ERROR_CLASSES describe_network_errors(error_description) when Chef::Exceptions::PrivateKeyMissing error_description.section("Private Key Not Found:",<<-E) Your private key could not be loaded. If the key file exists, ensure that it is readable by chef-client. E error_description.section("Relevant Config Settings:",<<-E) client_key "#{api_key}" E else error_description.section("Unexpected Error:","#{exception.class.name}: #{exception.message}") end end def humanize_http_exception(error_description) response = exception.response case response when Net::HTTPUnauthorized # TODO: this is where you'd see conflicts b/c of username/clientname stuff describe_401_error(error_description) when Net::HTTPForbidden # TODO: we're rescuing errors from Node.find_or_create # * could be no write on nodes container # * could be no read on the node error_description.section("Authorization Error",<<-E) Your client is not authorized to load the node data (HTTP 403). E error_description.section("Server Response:", format_rest_error) error_description.section("Possible Causes:",<<-E) * Your client (#{username}) may have misconfigured authorization permissions. E when Net::HTTPBadRequest describe_400_error(error_description) when Net::HTTPNotFound describe_404_error(error_description) when Net::HTTPInternalServerError describe_500_error(error_description) when Net::HTTPBadGateway, Net::HTTPServiceUnavailable describe_503_error(error_description) else describe_http_error(error_description) end end # Custom 404 error messaging. Users sometimes see 404s when they have # misconfigured server URLs, and the wrong one redirects to the new # one, e.g., PUT http://wrong.url/nodes/node-name becomes a GET after a # redirect. def describe_404_error(error_description) error_description.section("Resource Not Found:",<<-E) The server returned a HTTP 404. This usually indicates that your chef_server_url is incorrect. E error_description.section("Relevant Config Settings:",<<-E) chef_server_url "#{server_url}" E end def username config[:node_name] end def api_key config[:client_key] end def server_url config[:chef_server_url] end def clock_skew? exception.response.body =~ /synchronize the clock/i end end end end end chef-11.8.2/lib/chef/formatters/error_inspectors/api_error_formatting.rb0000644000004100000410000000664012254362222026552 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef module Formatters module APIErrorFormatting NETWORK_ERROR_CLASSES = [Errno::ECONNREFUSED, Timeout::Error, Errno::ETIMEDOUT, SocketError] def describe_network_errors(error_description) error_description.section("Networking Error:",<<-E) #{exception.message} Your chef_server_url may be misconfigured, or the network could be down. E error_description.section("Relevant Config Settings:",<<-E) chef_server_url "#{server_url}" E end def describe_401_error(error_description) if clock_skew? error_description.section("Authentication Error:",<<-E) Failed to authenticate to the chef server (http 401). The request failed because your clock has drifted by more than 15 minutes. Syncing your clock to an NTP Time source should resolve the issue. E else error_description.section("Authentication Error:",<<-E) Failed to authenticate to the chef server (http 401). E error_description.section("Server Response:", format_rest_error) error_description.section("Relevant Config Settings:",<<-E) chef_server_url "#{server_url}" node_name "#{username}" client_key "#{api_key}" If these settings are correct, your client_key may be invalid. E end end def describe_400_error(error_description) error_description.section("Invalid Request Data:",<<-E) The data in your request was invalid (HTTP 400). E error_description.section("Server Response:",format_rest_error) end def describe_500_error(error_description) error_description.section("Unknown Server Error:",<<-E) The server had a fatal error attempting to load the node data. E error_description.section("Server Response:", format_rest_error) end def describe_503_error(error_description) error_description.section("Server Unavailable","The Chef Server is temporarily unavailable") error_description.section("Server Response:", format_rest_error) end # Fallback for unexpected/uncommon http errors def describe_http_error(error_description) error_description.section("Unexpected API Request Failure:", format_rest_error) end # Parses JSON from the error response sent by Chef Server and returns the # error message def format_rest_error Array(Chef::JSONCompat.from_json(exception.response.body)["error"]).join('; ') rescue Exception exception.response.body end def username config[:node_name] end def api_key config[:client_key] end def server_url config[:chef_server_url] end def clock_skew? exception.response.body =~ /synchronize the clock/i end end end end chef-11.8.2/lib/chef/formatters/error_inspectors/run_list_expansion_error_inspector.rb0000644000004100000410000001021312254362222031547 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Author:: Tyler Cloke () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/formatters/error_inspectors/api_error_formatting' class Chef module Formatters module ErrorInspectors class RunListExpansionErrorInspector include APIErrorFormatting attr_reader :exception attr_reader :node def initialize(node, exception) @node, @exception = node, exception end def add_explanation(error_description) case exception when Errno::ECONNREFUSED, Timeout::Error, Errno::ETIMEDOUT, SocketError error_description.section("Networking Error:",<<-E) #{exception.message} Your chef_server_url may be misconfigured, or the network could be down. E when Net::HTTPServerException, Net::HTTPFatalError humanize_http_exception(error_description) when Chef::Exceptions::MissingRole describe_missing_role(error_description) else error_description.section("Unexpected Error:","#{exception.class.name}: #{exception.message}") end end def describe_missing_role(error_description) error_description.section("Missing Role(s) in Run List:", missing_roles_explained) original_run_list = node.run_list.map {|item| "* #{item}"}.join("\n") error_description.section("Original Run List", original_run_list) end def missing_roles_explained run_list_expansion.missing_roles_with_including_role.map do |role, includer| "* #{role} included by '#{includer}'" end.join("\n") end def run_list_expansion exception.expansion end def config Chef::Config end def humanize_http_exception(error_description) response = exception.response case response when Net::HTTPUnauthorized error_description.section("Authentication Error:",<<-E) Failed to authenticate to the chef server (http 401). E error_description.section("Server Response:", format_rest_error) error_description.section("Relevant Config Settings:",<<-E) chef_server_url "#{server_url}" node_name "#{username}" client_key "#{api_key}" If these settings are correct, your client_key may be invalid. E when Net::HTTPForbidden # TODO: we're rescuing errors from Node.find_or_create # * could be no write on nodes container # * could be no read on the node error_description.section("Authorization Error",<<-E) Your client is not authorized to load one or more of your roles (HTTP 403). E error_description.section("Server Response:", format_rest_error) error_description.section("Possible Causes:",<<-E) * Your client (#{username}) may have misconfigured authorization permissions. E when Net::HTTPInternalServerError error_description.section("Unknown Server Error:",<<-E) The server had a fatal error attempting to load a role. E error_description.section("Server Response:", format_rest_error) when Net::HTTPBadGateway, Net::HTTPServiceUnavailable error_description.section("Server Unavailable","The Chef Server is temporarily unavailable") error_description.section("Server Response:", format_rest_error) else error_description.section("Unexpected API Request Failure:", format_rest_error) end end end end end end chef-11.8.2/lib/chef/formatters/error_inspectors/cookbook_sync_error_inspector.rb0000644000004100000410000000477112254362222030502 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/formatters/error_inspectors/api_error_formatting' class Chef module Formatters module ErrorInspectors # == CookbookSyncErrorInspector # Generates human-friendly explanations for errors encountered during # cookbook sync. #-- # TODO: Not sure what errors are commonly seen during cookbook sync, so # the messaging is kinda generic. class CookbookSyncErrorInspector include APIErrorFormatting attr_reader :exception attr_reader :cookbooks def initialize(cookbooks, exception) @cookbooks, @exception = cookbooks, exception end def add_explanation(error_description) case exception when *NETWORK_ERROR_CLASSES describe_network_errors(error_description) when Net::HTTPServerException, Net::HTTPFatalError humanize_http_exception(error_description) else error_description.section("Unexpected Error:","#{exception.class.name}: #{exception.message}") end end def config Chef::Config end def humanize_http_exception(error_description) response = exception.response case response when Net::HTTPUnauthorized # TODO: this is where you'd see conflicts b/c of username/clientname stuff describe_401_error(error_description) when Net::HTTPBadRequest describe_400_error(error_description) when Net::HTTPNotFound when Net::HTTPInternalServerError describe_500_error(error_description) when Net::HTTPBadGateway, Net::HTTPServiceUnavailable describe_503_error(error_description) else describe_http_error(error_description) end end end end end end chef-11.8.2/lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb0000644000004100000410000001462412254362222031203 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/formatters/error_inspectors/api_error_formatting' class Chef module Formatters module ErrorInspectors class CookbookResolveErrorInspector attr_reader :exception attr_reader :expanded_run_list include APIErrorFormatting def initialize(expanded_run_list, exception) @expanded_run_list = expanded_run_list @exception = exception end def add_explanation(error_description) case exception when Net::HTTPServerException, Net::HTTPFatalError humanize_http_exception(error_description) when *NETWORK_ERROR_CLASSES describe_network_errors(error_description) else error_description.section("Unexpected Error:","#{exception.class.name}: #{exception.message}") end end def humanize_http_exception(error_description) response = exception.response case response when Net::HTTPUnauthorized # TODO: this is where you'd see conflicts b/c of username/clientname stuff describe_401_error(error_description) when Net::HTTPForbidden # TODO: we're rescuing errors from Node.find_or_create # * could be no write on nodes container # * could be no read on the node error_description.section("Authorization Error",<<-E) This client is not authorized to read some of the information required to access its coobooks (HTTP 403). To access its cookbooks, a client needs to be able to read its environment and all of the cookbooks in its expanded run list. E error_description.section("Expanded Run List:", expanded_run_list_ul) error_description.section("Server Response:", format_rest_error) when Net::HTTPPreconditionFailed describe_412_error(error_description) when Net::HTTPBadRequest describe_400_error(error_description) when Net::HTTPNotFound when Net::HTTPInternalServerError describe_500_error(error_description) when Net::HTTPBadGateway, Net::HTTPServiceUnavailable describe_503_error(error_description) else describe_http_error(error_description) end end def describe_412_error(error_description) explanation = "" error_reasons = extract_412_error_message # Prepare the error message if there is detailed information # about individual cookbooks. if !error_reasons.respond_to?(:key?) explanation << error_reasons.to_s else if error_reasons.key?("non_existent_cookbooks") && !Array(error_reasons["non_existent_cookbooks"]).empty? explanation << "The following cookbooks are required by the client but don't exist on the server:\n" Array(error_reasons["non_existent_cookbooks"]).each do |cookbook| explanation << "* #{cookbook}\n" end explanation << "\n" end if error_reasons.key?("cookbooks_with_no_versions") && !Array(error_reasons["cookbooks_with_no_versions"]).empty? explanation << "The following cookbooks exist on the server, but there is no version that meets\nthe version constraints in this environment:\n" Array(error_reasons["cookbooks_with_no_versions"]).each do |cookbook| explanation << "* #{cookbook}\n" end explanation << "\n" end end if !explanation.empty? error_description.section("Missing Cookbooks:", explanation) else # If we don't have any cookbook details print a more # generic error message. if error_reasons.respond_to?(:key?) && error_reasons["message"] explanation << "Error message: #{error_reasons["message"]}\n" end explanation << < ["nope"], # "cookbooks_with_no_versions" => [], # "message" => "Run list contains invalid items: no such cookbook nope."} def extract_412_error_message # Example: # "{\"error\":[\"{\\\"non_existent_cookbooks\\\":[\\\"nope\\\"],\\\"cookbooks_with_no_versions\\\":[],\\\"message\\\":\\\"Run list contains invalid items: no such cookbook nope.\\\"}\"]}" wrapped_error_message = attempt_json_parse(exception.response.body) unless wrapped_error_message.kind_of?(Hash) && wrapped_error_message.key?("error") return wrapped_error_message.to_s end error_description = Array(wrapped_error_message["error"]).first if error_description.kind_of?(Hash) return error_description end attempt_json_parse(error_description) end private def attempt_json_parse(maybe_json_string) Chef::JSONCompat.from_json(maybe_json_string) rescue Exception maybe_json_string end end end end end chef-11.8.2/lib/chef/handler.rb0000644000004100000410000001613712254362222016165 0ustar www-datawww-data#-- # Author:: Adam Jacob () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/client' require 'forwardable' class Chef # == Chef::Handler # The base class for an Exception or Notification Handler. Create your own # handler by subclassing Chef::Handler. When a Chef run fails with an # uncaught Exception, Chef will set the +run_status+ on your handler and call # +report+ # # ===Example: # # require 'net/smtp' # # module MyOrg # class OhNoes < Chef::Handler # # def report # # Create the email message # message = "From: Your Name \n" # message << "To: Destination Address \n" # message << "Subject: Chef Run Failure\n" # message << "Date: #{Time.now.rfc2822}\n\n" # # # The Node is available as +node+ # message << "Chef run failed on #{node.name}\n" # # +run_status+ is a value object with all of the run status data # message << "#{run_status.formatted_exception}\n" # # Join the backtrace lines. Coerce to an array just in case. # message << Array(backtrace).join("\n") # # # Send the email # Net::SMTP.start('your.smtp.server', 25) do |smtp| # smtp.send_message message, 'from@address', 'to@address' # end # end # # end # end # class Handler # The list of currently configured start handlers def self.start_handlers Array(Chef::Config[:start_handlers]) end # Run the start handlers. This will usually be called by a notification # from Chef::Client def self.run_start_handlers(run_status) Chef::Log.info("Running start handlers") start_handlers.each do |handler| handler.run_report_safely(run_status) end Chef::Log.info("Start handlers complete.") end # Wire up a notification to run the start handlers when the chef run # starts. Chef::Client.when_run_starts do |run_status| run_start_handlers(run_status) end # The list of currently configured report handlers def self.report_handlers Array(Chef::Config[:report_handlers]) end # Run the report handlers. This will usually be called by a notification # from Chef::Client def self.run_report_handlers(run_status) events = run_status.events events.handlers_start(report_handlers.size) Chef::Log.info("Running report handlers") report_handlers.each do |handler| handler.run_report_safely(run_status) events.handler_executed(handler) end events.handlers_completed Chef::Log.info("Report handlers complete") end # Wire up a notification to run the report handlers if the chef run # succeeds. Chef::Client.when_run_completes_successfully do |run_status| run_report_handlers(run_status) end # The list of currently configured exception handlers def self.exception_handlers Array(Chef::Config[:exception_handlers]) end # Run the exception handlers. Usually will be called by a notification # from Chef::Client when the run fails. def self.run_exception_handlers(run_status) events = run_status.events events.handlers_start(exception_handlers.size) Chef::Log.error("Running exception handlers") exception_handlers.each do |handler| handler.run_report_safely(run_status) events.handler_executed(handler) end events.handlers_completed Chef::Log.error("Exception handlers complete") end # Wire up a notification to run the exception handlers if the chef run fails. Chef::Client.when_run_fails do |run_status| run_exception_handlers(run_status) end extend Forwardable # The Chef::RunStatus object containing data about the Chef run. attr_reader :run_status ## # :method: start_time # # The time the chef run started def_delegator :@run_status, :start_time ## # :method: end_time # # The time the chef run ended def_delegator :@run_status, :end_time ## # :method: elapsed_time # # The time elapsed between the start and finish of the chef run def_delegator :@run_status, :elapsed_time ## # :method: run_context # # The Chef::RunContext object used by the chef run def_delegator :@run_status, :run_context ## # :method: exception # # The uncaught Exception that terminated the chef run, or nil if the run # completed successfully def_delegator :@run_status, :exception ## # :method: backtrace # # The backtrace captured by the uncaught exception that terminated the chef # run, or nil if the run completed successfully def_delegator :@run_status, :backtrace ## # :method: node # # The Chef::Node for this client run def_delegator :@run_status, :node ## # :method: all_resources # # An Array containing all resources in the chef run's resource_collection def_delegator :@run_status, :all_resources ## # :method: updated_resources # # An Array containing all resources that were updated during the chef run def_delegator :@run_status, :updated_resources ## # :method: success? # # Was the chef run successful? True if the chef run did not raise an # uncaught exception def_delegator :@run_status, :success? ## # :method: failed? # # Did the chef run fail? True if the chef run raised an uncaught exception def_delegator :@run_status, :failed? # The main entry point for report handling. Subclasses should override this # method with their own report handling logic. def report end # Runs the report handler, rescuing and logging any errors it may cause. # This ensures that all handlers get a chance to run even if one fails. # This method should not be overridden by subclasses unless you know what # you're doing. def run_report_safely(run_status) run_report_unsafe(run_status) rescue Exception => e Chef::Log.error("Report handler #{self.class.name} raised #{e.inspect}") Array(e.backtrace).each { |line| Chef::Log.error(line) } ensure @run_status = nil end # Runs the report handler without any error handling. This method should # not be used directly except in testing. def run_report_unsafe(run_status) @run_status = run_status report end # Return the Hash representation of the run_status def data @run_status.to_hash end end end chef-11.8.2/lib/chef/config.rb0000644000004100000410000005036012254362222016011 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Brown () # Author:: AJ Christensen () # Author:: Mark Mzyk () # Author:: Kyle Goodwin () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'chef/log' require 'chef/exceptions' require 'mixlib/config' require 'chef/util/selinux' require 'pathname' class Chef class Config extend Mixlib::Config # Evaluates the given string as config. # # +filename+ is used for context in stacktraces, but doesn't need to be the name of an actual file. def self.from_string(string, filename) self.instance_eval(string, filename, 1) end # Manages the chef secret session key # === Returns # :: A new or retrieved session key # def self.manage_secret_key newkey = nil if Chef::FileCache.has_key?("chef_server_cookie_id") newkey = Chef::FileCache.load("chef_server_cookie_id") else chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a newkey = "" 40.times { |i| newkey << chars[rand(chars.size-1)] } Chef::FileCache.store("chef_server_cookie_id", newkey) end newkey end def self.inspect configuration.inspect end def self.on_windows? RUBY_PLATFORM =~ /mswin|mingw|windows/ end BACKSLASH = '\\'.freeze def self.platform_path_separator if on_windows? File::ALT_SEPARATOR || BACKSLASH else File::SEPARATOR end end def self.path_join(*args) args = args.flatten args.inject do |joined_path, component| unless joined_path[-1,1] == platform_path_separator joined_path += platform_path_separator end joined_path += component end end def self.platform_specific_path(path) if on_windows? # turns /etc/chef/client.rb into C:/chef/client.rb system_drive = ENV['SYSTEMDRIVE'] ? ENV['SYSTEMDRIVE'] : "" path = File.join(system_drive, path.split('/')[2..-1]) # ensure all forward slashes are backslashes path.gsub!(File::SEPARATOR, (File::ALT_SEPARATOR || '\\')) end path end def self.add_formatter(name, file_path=nil) formatters << [name, file_path] end # Config file to load (client.rb, knife.rb, etc. defaults set differently in knife, chef-client, etc.) configurable(:config_file) default(:config_dir) do if local_mode path_join(user_home, ".chef#{platform_path_separator}") else config_file && ::File.dirname(config_file) end end # No config file (client.rb / knife.rb / etc.) will be loaded outside this path. # Major use case is tests, where we don't want to load the user's config files. configurable(:config_file_jail) default :formatters, [] # Override the config dispatch to set the value of multiple server options simultaneously # # === Parameters # url:: String to be set for all of the chef-server-api URL's # configurable(:chef_server_url).writes_value { |url| url.strip } # When you are using ActiveSupport, they monkey-patch 'daemonize' into Kernel. # So while this is basically identical to what method_missing would do, we pull # it up here and get a real method written so that things get dispatched # properly. configurable(:daemonize).writes_value { |v| v } # Override the config dispatch to set the value of log_location configuration option # # === Parameters # location:: Logging location as either an IO stream or string representing log file path # config_attr_writer :log_location do |location| if location.respond_to? :sync= location.sync = true location elsif location.respond_to? :to_str begin f = File.new(location.to_str, "a") f.sync = true rescue Errno::ENOENT raise Chef::Exceptions::ConfigurationError, "Failed to open or create log file at #{location.to_str}" end f end end # The root where all local chef object data is stored. cookbooks, data bags, # environments are all assumed to be in separate directories under this. # chef-solo uses these directories for input data. knife commands # that upload or download files (such as knife upload, knife role from file, # etc.) work. default :chef_repo_path do if self.configuration[:cookbook_path] if self.configuration[:cookbook_path].kind_of?(String) File.expand_path('..', self.configuration[:cookbook_path]) else self.configuration[:cookbook_path].map do |path| File.expand_path('..', path) end end else platform_specific_path("/var/chef") end end def self.find_chef_repo_path(cwd) # In local mode, we auto-discover the repo root by looking for a path with "cookbooks" under it. # This allows us to run config-free. path = cwd until File.directory?(path_join(path, "cookbooks")) new_path = File.expand_path('..', path) if new_path == path Chef::Log.warn("No cookbooks directory found at or above current directory. Assuming #{Dir.pwd}.") return Dir.pwd end path = new_path end Chef::Log.info("Auto-discovered chef repository at #{path}") path end def self.derive_path_from_chef_repo_path(child_path) if chef_repo_path.kind_of?(String) path_join(chef_repo_path, child_path) else chef_repo_path.map { |path| path_join(path, child_path)} end end # Location of acls on disk. String or array of strings. # Defaults to /acls. # Only applies to Enterprise Chef commands. default(:acl_path) { derive_path_from_chef_repo_path('acls') } # Location of clients on disk. String or array of strings. # Defaults to /acls. default(:client_path) { derive_path_from_chef_repo_path('clients') } # Location of cookbooks on disk. String or array of strings. # Defaults to /cookbooks. If chef_repo_path # is not specified, this is set to [/var/chef/cookbooks, /var/chef/site-cookbooks]). default(:cookbook_path) do if self.configuration[:chef_repo_path] derive_path_from_chef_repo_path('cookbooks') else Array(derive_path_from_chef_repo_path('cookbooks')).flatten + Array(derive_path_from_chef_repo_path('site-cookbooks')).flatten end end # Location of containers on disk. String or array of strings. # Defaults to /containers. # Only applies to Enterprise Chef commands. default(:container_path) { derive_path_from_chef_repo_path('containers') } # Location of data bags on disk. String or array of strings. # Defaults to /data_bags. default(:data_bag_path) { derive_path_from_chef_repo_path('data_bags') } # Location of environments on disk. String or array of strings. # Defaults to /environments. default(:environment_path) { derive_path_from_chef_repo_path('environments') } # Location of groups on disk. String or array of strings. # Defaults to /groups. # Only applies to Enterprise Chef commands. default(:group_path) { derive_path_from_chef_repo_path('groups') } # Location of nodes on disk. String or array of strings. # Defaults to /nodes. default(:node_path) { derive_path_from_chef_repo_path('nodes') } # Location of roles on disk. String or array of strings. # Defaults to /roles. default(:role_path) { derive_path_from_chef_repo_path('roles') } # Location of users on disk. String or array of strings. # Defaults to /users. # Does not apply to Enterprise Chef commands. default(:user_path) { derive_path_from_chef_repo_path('users') } # Turn on "path sanity" by default. See also: http://wiki.opscode.com/display/chef/User+Environment+PATH+Sanity default :enforce_path_sanity, true # Formatted Chef Client output is a beta feature, disabled by default: default :formatter, "null" # The number of times the client should retry when registering with the server default :client_registration_retries, 5 # An array of paths to search for knife exec scripts if they aren't in the current directory default :script_path, [] # The root of all caches (checksums, cache and backup). If local mode is on, # this is under the user's home directory. default(:cache_path) do if local_mode "#{config_dir}local-mode-cache" else platform_specific_path("/var/chef") end end # Where cookbook files are stored on the server (by content checksum) default(:checksum_path) { path_join(cache_path, "checksums") } # Where chef's cache files should be stored default(:file_cache_path) { path_join(cache_path, "cache") } # Where backups of chef-managed files should go default(:file_backup_path) { path_join(cache_path, "backup") } # The chef-client (or solo) lockfile. # # If your `file_cache_path` resides on a NFS (or non-flock()-supporting # fs), it's recommended to set this to something like # '/tmp/chef-client-running.pid' default(:lockfile) { path_join(file_cache_path, "chef-client-running.pid") } ## Daemonization Settings ## # What user should Chef run as? default :user, nil default :group, nil default :umask, 0022 # Valid log_levels are: # * :debug # * :info # * :warn # * :fatal # These work as you'd expect. There is also a special `:auto` setting. # When set to :auto, Chef will auto adjust the log verbosity based on # context. When a tty is available (usually becase the user is running chef # in a console), the log level is set to :warn, and output formatters are # used as the primary mode of output. When a tty is not available, the # logger is the primary mode of output, and the log level is set to :info default :log_level, :auto # Using `force_formatter` causes chef to default to formatter output when STDOUT is not a tty default :force_formatter, false # Using `force_logger` causes chef to default to logger output when STDOUT is a tty default :force_logger, false default :http_retry_count, 5 default :http_retry_delay, 5 default :interval, nil default :once, nil default :json_attribs, nil default :log_location, STDOUT # toggle info level log items that can create a lot of output default :verbose_logging, true default :node_name, nil default :diff_disabled, false default :diff_filesize_threshold, 10000000 default :diff_output_threshold, 1000000 default :local_mode, false default :pid_file, nil config_context :chef_zero do config_strict_mode true default(:enabled) { Chef::Config.local_mode } default :port, 8889 end default :chef_server_url, "https://localhost:443" default :rest_timeout, 300 default :yum_timeout, 900 default :solo, false default :splay, nil default :why_run, false default :color, false default :client_fork, true default :enable_reporting, true default :enable_reporting_url_fatals, false # Set these to enable SSL authentication / mutual-authentication # with the server # Client side SSL cert/key for mutual auth default :ssl_client_cert, nil default :ssl_client_key, nil # Whether or not to verify the SSL cert for all HTTPS requests. If set to # :verify_peer, all HTTPS requests will be validated regardless of other # SSL verification settings. default :ssl_verify_mode, :verify_none # Whether or not to verify the SSL cert for HTTPS requests to the Chef # server API. If set to `true`, the server's cert will be validated # regardless of the :ssl_verify_mode setting. default :verify_api_cert, false # Path to the default CA bundle files. default :ssl_ca_path, nil default(:ssl_ca_file) do if on_windows? and embedded_path = embedded_dir cacert_path = File.join(embedded_path, "ssl/certs/cacert.pem") cacert_path if File.exist?(cacert_path) else nil end end # A directory that contains additional SSL certificates to trust. Any # certificates in this directory will be added to whatever CA bundle ruby # is using. Use this to add self-signed certs for your Chef Server or local # HTTP file servers. default(:trusted_certs_dir) { config_dir && path_join(config_dir, "trusted_certs") } # Where should chef-solo download recipes from? default :recipe_url, nil # Sets the version of the signed header authentication protocol to use (see # the 'mixlib-authorization' project for more detail). Currently, versions # 1.0 and 1.1 are available; however, the chef-server must first be # upgraded to support version 1.1 before clients can begin using it. # # Version 1.1 of the protocol is required when using a `node_name` greater # than ~90 bytes (~90 ascii characters), so chef-client will automatically # switch to using version 1.1 when `node_name` is too large for the 1.0 # protocol. If you intend to use large node names, ensure that your server # supports version 1.1. Automatic detection of large node names means that # users will generally not need to manually configure this. # # In the future, this configuration option may be replaced with an # automatic negotiation scheme. default :authentication_protocol_version, "1.0" # This key will be used to sign requests to the Chef server. This location # must be writable by Chef during initial setup when generating a client # identity on the server. # # The chef-server will look up the public key for the client using the # `node_name` of the client. # # If chef-zero is enabled, this defaults to nil (no authentication). default(:client_key) { chef_zero.enabled ? nil : platform_specific_path("/etc/chef/client.pem") } # This secret is used to decrypt encrypted data bag items. default(:encrypted_data_bag_secret) do # We have to check for the existence of the default file before setting it # since +Chef::Config[:encrypted_data_bag_secret]+ is read by older # bootstrap templates to determine if the local secret should be uploaded to # node being bootstrapped. This should be removed in Chef 12. if File.exist?(platform_specific_path("/etc/chef/encrypted_data_bag_secret")) platform_specific_path("/etc/chef/encrypted_data_bag_secret") else nil end end # As of Chef 11.0, version "1" is the default encrypted data bag item # format. Version "2" is available which adds encrypt-then-mac protection. # To maintain compatibility, versions other than 1 must be opt-in. # # Set this to `2` if you have chef-client 11.6.0+ in your infrastructure: default :data_bag_encrypt_version, 1 # When reading data bag items, any supported version is accepted. However, # if all encrypted data bags have been generated with the version 2 format, # it is recommended to disable support for earlier formats to improve # security. For example, the version 2 format is identical to version 1 # except for the addition of an HMAC, so an attacker with MITM capability # could downgrade an encrypted data bag to version 1 as part of an attack. default :data_bag_decrypt_minimum_version, 0 # If there is no file in the location given by `client_key`, chef-client # will temporarily use the "validator" identity to generate one. If the # `client_key` is not present and the `validation_key` is also not present, # chef-client will not be able to authenticate to the server. # # The `validation_key` is never used if the `client_key` exists. # # If chef-zero is enabled, this defaults to nil (no authentication). default(:validation_key) { chef_zero.enabled ? nil : platform_specific_path("/etc/chef/validation.pem") } default :validation_client_name, "chef-validator" # Zypper package provider gpg checks. Set to true to enable package # gpg signature checking. This will be default in the # future. Setting to false disables the warnings. # Leaving this set to nil or false is a security hazard! default :zypper_check_gpg, nil # Report Handlers default :report_handlers, [] # Exception Handlers default :exception_handlers, [] # Start handlers default :start_handlers, [] # Syntax Check Cache. Knife keeps track of files that is has already syntax # checked by storing files in this directory. `syntax_check_cache_path` is # the new (and preferred) configuration setting. If not set, knife will # fall back to using cache_options[:path], which is deprecated but exists in # many client configs generated by pre-Chef-11 bootstrappers. default(:syntax_check_cache_path) { cache_options[:path] } # Deprecated: default(:cache_options) { { :path => path_join(file_cache_path, "checksums") } } # Set to false to silence Chef 11 deprecation warnings: default :chef11_deprecation_warnings, true # knife configuration data config_context :knife do default :ssh_port, nil default :ssh_user, nil default :ssh_attribute, nil default :ssh_gateway, nil default :bootstrap_version, nil default :bootstrap_proxy, nil default :identity_file, nil default :host_key_verify, nil default :forward_agent, nil default :sort_status_reverse, nil default :hints, {} end # Those lists of regular expressions define what chef considers a # valid user and group name if RUBY_PLATFORM =~ /mswin|mingw|windows/ # From http://technet.microsoft.com/en-us/library/cc776019(WS.10).aspx principal_valid_regex_part = '[^"\/\\\\\[\]\:;|=,+*?<>]+' default :user_valid_regex, [ /^(#{principal_valid_regex_part}\\)?#{principal_valid_regex_part}$/ ] default :group_valid_regex, [ /^(#{principal_valid_regex_part}\\)?#{principal_valid_regex_part}$/ ] default :fatal_windows_admin_check, false else default :user_valid_regex, [ /^([-a-zA-Z0-9_.]+[\\@]?[-a-zA-Z0-9_.]+)$/, /^\d+$/ ] default :group_valid_regex, [ /^([-a-zA-Z0-9_.\\@^ ]+)$/, /^\d+$/ ] end # returns a platform specific path to the user home dir windows_home_path = ENV['SYSTEMDRIVE'] + ENV['HOMEPATH'] if ENV['SYSTEMDRIVE'] && ENV['HOMEPATH'] default :user_home, (ENV['HOME'] || windows_home_path || ENV['USERPROFILE']) # Enable file permission fixup for selinux. Fixup will be done # only if selinux is enabled in the system. default :enable_selinux_file_permission_fixup, true # Use atomic updates (i.e. move operation) while updating contents # of the files resources. When set to false copy operation is # used to update files. default :file_atomic_update, true # If false file staging is will be done via tempfiles that are # created under ENV['TMP'] otherwise tempfiles will be created in # the directory that files are going to reside. default :file_staging_uses_destdir, false # If installed via an omnibus installer, this gives the path to the # "embedded" directory which contains all of the software packaged with # omnibus. This is used to locate the cacert.pem file on windows. def self.embedded_dir Pathname.new(_this_file).ascend do |path| if path.basename.to_s == "embedded" return path.to_s end end nil end # Path to this file in the current install. def self._this_file File.expand_path(__FILE__) end end end chef-11.8.2/lib/chef/knife/0000755000004100000410000000000012254362222015307 5ustar www-datawww-datachef-11.8.2/lib/chef/knife/diff.rb0000644000004100000410000000455412254362222016554 0ustar www-datawww-datarequire 'chef/chef_fs/knife' class Chef class Knife class Diff < Chef::ChefFS::Knife banner "knife diff PATTERNS" category "path-based" deps do require 'chef/chef_fs/command_line' end option :recurse, :long => '--[no-]recurse', :boolean => true, :default => true, :description => "List directories recursively." option :name_only, :long => '--name-only', :boolean => true, :description => "Only show names of modified files." option :name_status, :long => '--name-status', :boolean => true, :description => "Only show names and statuses of modified files: Added, Deleted, Modified, and Type Changed." option :diff_filter, :long => '--diff-filter=[(A|D|M|T)...[*]]', :description => "Select only files that are Added (A), Deleted (D), Modified (M), or have their type (i.e. regular file, directory) changed (T). Any combination of the filter characters (including none) can be used. When * (All-or-none) is added to the combination, all paths are selected if there is any file that matches other criteria in the comparison; if there is no file that matches other criteria, nothing is selected." option :cookbook_version, :long => '--cookbook-version VERSION', :description => 'Version of cookbook to download (if there are multiple versions and cookbook_versions is false)' def run if config[:name_only] output_mode = :name_only end if config[:name_status] output_mode = :name_status end patterns = pattern_args_from(name_args.length > 0 ? name_args : [ "" ]) # Get the matches (recursively) error = false begin patterns.each do |pattern| found_error = Chef::ChefFS::CommandLine.diff_print(pattern, chef_fs, local_fs, config[:recurse] ? nil : 1, output_mode, proc { |entry| format_path(entry) }, config[:diff_filter], ui ) do |diff| stdout.print diff end error = true if found_error end rescue Chef::ChefFS::FileSystem::OperationFailedError => e ui.error "Failed on #{format_path(e.entry)} in #{e.operation}: #{e.message}" error = true end if error exit 1 end end end end end chef-11.8.2/lib/chef/knife/deps.rb0000644000004100000410000001125312254362222016571 0ustar www-datawww-datarequire 'chef/chef_fs/knife' class Chef class Knife class Deps < Chef::ChefFS::Knife banner "knife deps PATTERN1 [PATTERNn]" category "path-based" deps do require 'chef/chef_fs/file_system' require 'chef/run_list' end option :recurse, :long => '--[no-]recurse', :boolean => true, :description => "List dependencies recursively (default: true). Only works with --tree." option :tree, :long => '--tree', :boolean => true, :description => "Show dependencies in a visual tree. May show duplicates." option :remote, :long => '--remote', :boolean => true, :description => "List dependencies on the server instead of the local filesystem" attr_accessor :exit_code def run if config[:recurse] == false && !config[:tree] ui.error "--no-recurse requires --tree" exit(1) end config[:recurse] = true if config[:recurse].nil? @root = config[:remote] ? chef_fs : local_fs dependencies = {} pattern_args.each do |pattern| Chef::ChefFS::FileSystem.list(@root, pattern).each do |entry| if config[:tree] print_dependencies_tree(entry, dependencies) else print_flattened_dependencies(entry, dependencies) end end end exit exit_code if exit_code end def print_flattened_dependencies(entry, dependencies) if !dependencies[entry.path] dependencies[entry.path] = get_dependencies(entry) dependencies[entry.path].each do |child| child_entry = Chef::ChefFS::FileSystem.resolve_path(@root, child) print_flattened_dependencies(child_entry, dependencies) end output format_path(entry) end end def print_dependencies_tree(entry, dependencies, printed = {}, depth = 0) dependencies[entry.path] = get_dependencies(entry) if !dependencies[entry.path] output "#{' '*depth}#{format_path(entry)}" if !printed[entry.path] && (config[:recurse] || depth == 0) printed[entry.path] = true dependencies[entry.path].each do |child| child_entry = Chef::ChefFS::FileSystem.resolve_path(@root, child) print_dependencies_tree(child_entry, dependencies, printed, depth+1) end end end def get_dependencies(entry) begin if entry.parent && entry.parent.path == '/cookbooks' return entry.chef_object.metadata.dependencies.keys.map { |cookbook| "/cookbooks/#{cookbook}" } elsif entry.parent && entry.parent.path == '/nodes' node = JSON.parse(entry.read, :create_additions => false) result = [] if node['chef_environment'] && node['chef_environment'] != '_default' result << "/environments/#{node['chef_environment']}.json" end if node['run_list'] result += dependencies_from_runlist(node['run_list']) end result elsif entry.parent && entry.parent.path == '/roles' role = JSON.parse(entry.read, :create_additions => false) result = [] if role['run_list'] dependencies_from_runlist(role['run_list']).each do |dependency| result << dependency if !result.include?(dependency) end end if role['env_run_lists'] role['env_run_lists'].each_pair do |env,run_list| dependencies_from_runlist(run_list).each do |dependency| result << dependency if !result.include?(dependency) end end end result elsif !entry.exists? raise Chef::ChefFS::FileSystem::NotFoundError.new(entry) else [] end rescue Chef::ChefFS::FileSystem::NotFoundError => e ui.error "#{format_path(e.entry)}: No such file or directory" self.exit_code = 2 [] end end def dependencies_from_runlist(run_list) chef_run_list = Chef::RunList.new chef_run_list.reset!(run_list) chef_run_list.map do |run_list_item| case run_list_item.type when :role "/roles/#{run_list_item.name}.json" when :recipe if run_list_item.name =~ /(.+)::[^:]*/ "/cookbooks/#{$1}" else "/cookbooks/#{run_list_item.name}" end else raise "Unknown run list item type #{run_list_item.type}" end end end end end end chef-11.8.2/lib/chef/knife/client_edit.rb0000644000004100000410000000221712254362222020121 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class ClientEdit < Knife deps do require 'chef/api_client' require 'chef/json_compat' end banner "knife client edit CLIENT (options)" def run @client_name = @name_args[0] if @client_name.nil? show_usage ui.fatal("You must specify a client name") exit 1 end edit_object(Chef::ApiClient, @client_name) end end end end chef-11.8.2/lib/chef/knife/show.rb0000644000004100000410000000313512254362222016616 0ustar www-datawww-datarequire 'chef/chef_fs/knife' class Chef class Knife class Show < Chef::ChefFS::Knife banner "knife show [PATTERN1 ... PATTERNn]" category "path-based" deps do require 'chef/chef_fs/file_system' require 'chef/chef_fs/file_system/not_found_error' end option :local, :long => '--local', :boolean => true, :description => "Show local files instead of remote" def run # Get the matches (recursively) error = false entry_values = parallelize(pattern_args, :flatten => true) do |pattern| parallelize(Chef::ChefFS::FileSystem.list(config[:local] ? local_fs : chef_fs, pattern)) do |entry| if entry.dir? ui.error "#{format_path(entry)}: is a directory" if pattern.exact_path error = true nil else begin [entry, entry.read] rescue Chef::ChefFS::FileSystem::OperationNotAllowedError => e ui.error "#{format_path(e.entry)}: #{e.reason}." error = true nil rescue Chef::ChefFS::FileSystem::NotFoundError => e ui.error "#{format_path(e.entry)}: No such file or directory" error = true nil end end end end entry_values.each do |entry, value| if entry output "#{format_path(entry)}:" output(format_for_display(value)) end end if error exit 1 end end end end end chef-11.8.2/lib/chef/knife/cookbook_site_vendor.rb0000644000004100000410000000227612254362222022052 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' require 'chef/knife/cookbook_site_install' class Chef::Knife::CookbookSiteVendor < Chef::Knife::CookbookSiteInstall def self.load_deps superclass.load_deps end def self.options=(new_opts) superclass.options = new_opts end def self.options superclass.options end banner(<<-B) ************************************************* DEPRECATED: please use knife cookbook site install ************************************************* #{superclass.banner} B category 'deprecated' end chef-11.8.2/lib/chef/knife/ssh.rb0000644000004100000410000004105612254362222016437 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class Ssh < Knife deps do require 'net/ssh' require 'net/ssh/multi' require 'chef/monkey_patches/net-ssh-multi' require 'readline' require 'chef/exceptions' require 'chef/search/query' require 'chef/mixin/shell_out' require 'mixlib/shellout' end include Chef::Mixin::ShellOut attr_writer :password banner "knife ssh QUERY COMMAND (options)" option :concurrency, :short => "-C NUM", :long => "--concurrency NUM", :description => "The number of concurrent connections", :default => nil, :proc => lambda { |o| o.to_i } option :attribute, :short => "-a ATTR", :long => "--attribute ATTR", :description => "The attribute to use for opening the connection - default depends on the context", :proc => Proc.new { |key| Chef::Config[:knife][:ssh_attribute] = key.strip } option :manual, :short => "-m", :long => "--manual-list", :boolean => true, :description => "QUERY is a space separated list of servers", :default => false option :ssh_user, :short => "-x USERNAME", :long => "--ssh-user USERNAME", :description => "The ssh username" option :ssh_password, :short => "-P PASSWORD", :long => "--ssh-password PASSWORD", :description => "The ssh password" option :ssh_port, :short => "-p PORT", :long => "--ssh-port PORT", :description => "The ssh port", :proc => Proc.new { |key| Chef::Config[:knife][:ssh_port] = key.strip } option :ssh_gateway, :short => "-G GATEWAY", :long => "--ssh-gateway GATEWAY", :description => "The ssh gateway", :proc => Proc.new { |key| Chef::Config[:knife][:ssh_gateway] = key.strip } option :forward_agent, :short => "-A", :long => "--forward-agent", :description => "Enable SSH agent forwarding", :boolean => true option :identity_file, :short => "-i IDENTITY_FILE", :long => "--identity-file IDENTITY_FILE", :description => "The SSH identity file used for authentication" option :host_key_verify, :long => "--[no-]host-key-verify", :description => "Verify host key, enabled by default.", :boolean => true, :default => true def session config[:on_error] ||= :skip ssh_error_handler = Proc.new do |server| if config[:manual] node_name = server.host else @action_nodes.each do |n| node_name = n if format_for_display(n)[config[:attribute]] == server.host end end case config[:on_error] when :skip ui.warn "Failed to connect to #{node_name} -- #{$!.class.name}: #{$!.message}" $!.backtrace.each { |l| Chef::Log.debug(l) } when :raise #Net::SSH::Multi magic to force exception to be re-raised. throw :go, :raise end end @session ||= Net::SSH::Multi.start(:concurrent_connections => config[:concurrency], :on_error => ssh_error_handler) end def configure_gateway config[:ssh_gateway] ||= Chef::Config[:knife][:ssh_gateway] if config[:ssh_gateway] gw_host, gw_user = config[:ssh_gateway].split('@').reverse gw_host, gw_port = gw_host.split(':') gw_opts = gw_port ? { :port => gw_port } : {} session.via(gw_host, gw_user || config[:ssh_user], gw_opts) end rescue Net::SSH::AuthenticationFailed user = gw_user || config[:ssh_user] prompt = "Enter the password for #{user}@#{gw_host}: " gw_opts.merge!(:password => prompt_for_password(prompt)) session.via(gw_host, user, gw_opts) end def configure_session list = case config[:manual] when true @name_args[0].split(" ") when false r = Array.new q = Chef::Search::Query.new @action_nodes = q.search(:node, @name_args[0])[0] @action_nodes.each do |item| # we should skip the loop to next iteration if the item returned by the search is nil next if item.nil? # if a command line attribute was not passed, and we have a cloud public_hostname, use that. # see #configure_attribute for the source of config[:attribute] and config[:override_attribute] if !config[:override_attribute] && item[:cloud] and item[:cloud][:public_hostname] i = item[:cloud][:public_hostname] elsif config[:override_attribute] i = extract_nested_value(item, config[:override_attribute]) else i = extract_nested_value(item, config[:attribute]) end # next if we couldn't find the specified attribute in the returned node object next if i.nil? r.push(i) end r end if list.length == 0 if @action_nodes.length == 0 ui.fatal("No nodes returned from search!") else ui.fatal("#{@action_nodes.length} #{@action_nodes.length > 1 ? "nodes":"node"} found, " + "but does not have the required attribute to establish the connection. " + "Try setting another attribute to open the connection using --attribute.") end exit 10 end session_from_list(list) end def session_from_list(list) list.each do |item| Chef::Log.debug("Adding #{item}") session_opts = {} ssh_config = Net::SSH.configuration_for(item) # Chef::Config[:knife][:ssh_user] is parsed in #configure_user and written to config[:ssh_user] user = config[:ssh_user] || ssh_config[:user] hostspec = user ? "#{user}@#{item}" : item session_opts[:keys] = File.expand_path(config[:identity_file]) if config[:identity_file] session_opts[:keys_only] = true if config[:identity_file] session_opts[:password] = config[:ssh_password] if config[:ssh_password] session_opts[:forward_agent] = config[:forward_agent] session_opts[:port] = config[:ssh_port] || Chef::Config[:knife][:ssh_port] || ssh_config[:port] session_opts[:logger] = Chef::Log.logger if Chef::Log.level == :debug if !config[:host_key_verify] session_opts[:paranoid] = false session_opts[:user_known_hosts_file] = "/dev/null" end session.use(hostspec, session_opts) @longest = item.length if item.length > @longest end session end def fixup_sudo(command) command.sub(/^sudo/, 'sudo -p \'knife sudo password: \'') end def print_data(host, data) @buffers ||= {} if leftover = @buffers[host] @buffers[host] = nil print_data(host, leftover + data) else if newline_index = data.index("\n") line = data.slice!(0...newline_index) data.slice!(0) print_line(host, line) print_data(host, data) else @buffers[host] = data end end end def print_line(host, data) padding = @longest - host.length str = ui.color(host, :cyan) + (" " * (padding + 1)) + data ui.msg(str) end def ssh_command(command, subsession=nil) exit_status = 0 subsession ||= session command = fixup_sudo(command) command.force_encoding('binary') if command.respond_to?(:force_encoding) subsession.open_channel do |ch| ch.request_pty ch.exec command do |ch, success| raise ArgumentError, "Cannot execute #{command}" unless success ch.on_data do |ichannel, data| print_data(ichannel[:host], data) if data =~ /^knife sudo password: / print_data(ichannel[:host], "\n") ichannel.send_data("#{get_password}\n") end end ch.on_request "exit-status" do |ichannel, data| exit_status = [exit_status, data.read_long].max end end end session.loop exit_status end def get_password @password ||= prompt_for_password end def prompt_for_password(prompt = "Enter your password: ") ui.ask(prompt) { |q| q.echo = false } end # Present the prompt and read a single line from the console. It also # detects ^D and returns "exit" in that case. Adds the input to the # history, unless the input is empty. Loops repeatedly until a non-empty # line is input. def read_line loop do command = reader.readline("#{ui.color('knife-ssh>', :bold)} ", true) if command.nil? command = "exit" puts(command) else command.strip! end unless command.empty? return command end end end def reader Readline end def interactive puts "Connected to #{ui.list(session.servers_for.collect { |s| ui.color(s.host, :cyan) }, :inline, " and ")}" puts puts "To run a command on a list of servers, do:" puts " on SERVER1 SERVER2 SERVER3; COMMAND" puts " Example: on latte foamy; echo foobar" puts puts "To exit interactive mode, use 'quit!'" puts while 1 command = read_line case command when 'quit!' puts 'Bye!' break when /^on (.+?); (.+)$/ raw_list = $1.split(" ") server_list = Array.new session.servers.each do |session_server| server_list << session_server if raw_list.include?(session_server.host) end command = $2 ssh_command(command, session.on(*server_list)) else ssh_command(command) end end end def screen tf = Tempfile.new("knife-ssh-screen") if File.exist? "#{ENV["HOME"]}/.screenrc" tf.puts("source #{ENV["HOME"]}/.screenrc") end tf.puts("caption always '%-Lw%{= BW}%50>%n%f* %t%{-}%+Lw%<'") tf.puts("hardstatus alwayslastline 'knife ssh #{@name_args[0]}'") window = 0 session.servers_for.each do |server| tf.print("screen -t \"#{server.host}\" #{window} ssh ") tf.print("-i #{config[:identity_file]} ") if config[:identity_file] server.user ? tf.puts("#{server.user}@#{server.host}") : tf.puts(server.host) window += 1 end tf.close exec("screen -c #{tf.path}") end def tmux ssh_dest = lambda do |server| identity = "-i #{config[:identity_file]} " if config[:identity_file] prefix = server.user ? "#{server.user}@" : "" "'ssh #{identity}#{prefix}#{server.host}'" end new_window_cmds = lambda do if session.servers_for.size > 1 [""] + session.servers_for[1..-1].map do |server| "new-window -a -n '#{server.host}' #{ssh_dest.call(server)}" end else [] end.join(" \\; ") end tmux_name = "'knife ssh #{@name_args[0].gsub(/:/,'=')}'" begin server = session.servers_for.first cmd = ["tmux new-session -d -s #{tmux_name}", "-n '#{server.host}'", ssh_dest.call(server), new_window_cmds.call].join(" ") shell_out!(cmd) exec("tmux attach-session -t #{tmux_name}") rescue Chef::Exceptions::Exec end end def macterm begin require 'appscript' rescue LoadError STDERR.puts "you need the rb-appscript gem to use knife ssh macterm. `(sudo) gem install rb-appscript` to install" raise end Appscript.app("/Applications/Utilities/Terminal.app").windows.first.activate Appscript.app("System Events").application_processes["Terminal.app"].keystroke("n", :using=>:command_down) term = Appscript.app('Terminal') window = term.windows.first.get (session.servers_for.size - 1).times do |i| window.activate Appscript.app("System Events").application_processes["Terminal.app"].keystroke("t", :using=>:command_down) end session.servers_for.each_with_index do |server, tab_number| cmd = "unset PROMPT_COMMAND; echo -e \"\\033]0;#{server.host}\\007\"; ssh #{server.user ? "#{server.user}@#{server.host}" : server.host}" Appscript.app('Terminal').do_script(cmd, :in => window.tabs[tab_number + 1].get) end end def configure_attribute # Setting 'knife[:ssh_attribute] = "foo"' in knife.rb => Chef::Config[:knife][:ssh_attribute] == 'foo' # Running 'knife ssh -a foo' => both Chef::Config[:knife][:ssh_attribute] && config[:attribute] == foo # Thus we can differentiate between a config file value and a command line override at this point by checking config[:attribute] # We can tell here if fqdn was passed from the command line, rather than being the default, by checking config[:attribute] # However, after here, we cannot tell these things, so we must preserve config[:attribute] config[:override_attribute] = config[:attribute] || Chef::Config[:knife][:ssh_attribute] config[:attribute] = (Chef::Config[:knife][:ssh_attribute] || config[:attribute] || "fqdn").strip end def cssh cssh_cmd = nil %w[csshX cssh].each do |cmd| begin # Unix and Mac only cssh_cmd = shell_out!("which #{cmd}").stdout.strip break rescue Mixlib::ShellOut::ShellCommandFailed end end raise Chef::Exceptions::Exec, "no command found for cssh" unless cssh_cmd session.servers_for.each do |server| cssh_cmd << " #{server.user ? "#{server.user}@#{server.host}" : server.host}" end Chef::Log.debug("starting cssh session with command: #{cssh_cmd}") exec(cssh_cmd) end def get_stripped_unfrozen_value(value) return nil if value.nil? value.strip end def configure_user config[:ssh_user] = get_stripped_unfrozen_value(config[:ssh_user] || Chef::Config[:knife][:ssh_user]) end def configure_identity_file config[:identity_file] = get_stripped_unfrozen_value(config[:identity_file] || Chef::Config[:knife][:ssh_identity_file]) end def extract_nested_value(data_structure, path_spec) ui.presenter.extract_nested_value(data_structure, path_spec) end def run extend Chef::Mixin::Command @longest = 0 configure_attribute configure_user configure_identity_file configure_gateway configure_session exit_status = case @name_args[1] when "interactive" interactive when "screen" screen when "tmux" tmux when "macterm" macterm when "cssh" cssh when "csshx" Chef::Log.warn("knife ssh csshx will be deprecated in a future release") Chef::Log.warn("please use knife ssh cssh instead") cssh else ssh_command(@name_args[1..-1].join(" ")) end session.close if exit_status != 0 exit exit_status else exit_status end end end end end chef-11.8.2/lib/chef/knife/role_show.rb0000644000004100000410000000243112254362222017635 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class RoleShow < Knife include Knife::Core::MultiAttributeReturnOption deps do require 'chef/node' require 'chef/json_compat' end banner "knife role show ROLE (options)" def run @role_name = @name_args[0] if @role_name.nil? show_usage ui.fatal("You must specify a role name") exit 1 end role = Chef::Role.load(@role_name) output(format_for_display(config[:environment] ? role.environment(config[:environment]) : role)) end end end end chef-11.8.2/lib/chef/knife/user_reregister.rb0000644000004100000410000000302612254362222021046 0ustar www-datawww-data# # Author:: Steven Danna () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class UserReregister < Knife deps do require 'chef/user' require 'chef/json_compat' end banner "knife user reregister USER (options)" option :file, :short => "-f FILE", :long => "--file FILE", :description => "Write the private key to a file" def run @user_name = @name_args[0] if @user_name.nil? show_usage ui.fatal("You must specify a user name") exit 1 end user = Chef::User.load(@user_name).reregister Chef::Log.debug("Updated user data: #{user.inspect}") key = user.private_key if config[:file] File.open(config[:file], "w") do |f| f.print(key) end else ui.msg key end end end end end chef-11.8.2/lib/chef/knife/cookbook_upload.rb0000644000004100000410000002571012254362222021013 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Walters () # Author:: Nuo Yan () # Copyright:: Copyright (c) 2009, 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' require 'chef/cookbook_uploader' class Chef class Knife class CookbookUpload < Knife CHECKSUM = "checksum" MATCH_CHECKSUM = /[0-9a-f]{32,}/ deps do require 'chef/exceptions' require 'chef/cookbook_loader' require 'chef/cookbook_uploader' end banner "knife cookbook upload [COOKBOOKS...] (options)" option :cookbook_path, :short => "-o PATH:PATH", :long => "--cookbook-path PATH:PATH", :description => "A colon-separated path to look for cookbooks in", :proc => lambda { |o| o.split(":") } option :freeze, :long => '--freeze', :description => 'Freeze this version of the cookbook so that it cannot be overwritten', :boolean => true option :all, :short => "-a", :long => "--all", :description => "Upload all cookbooks, rather than just a single cookbook" option :force, :long => '--force', :boolean => true, :description => "Update cookbook versions even if they have been frozen" option :environment, :short => '-E', :long => '--environment ENVIRONMENT', :description => "Set ENVIRONMENT's version dependency match the version you're uploading.", :default => nil option :depends, :short => "-d", :long => "--include-dependencies", :description => "Also upload cookbook dependencies" def run # Sanity check before we load anything from the server unless config[:all] if @name_args.empty? show_usage ui.fatal("You must specify the --all flag or at least one cookbook name") exit 1 end end config[:cookbook_path] ||= Chef::Config[:cookbook_path] if @name_args.empty? and ! config[:all] show_usage ui.fatal("You must specify the --all flag or at least one cookbook name") exit 1 end assert_environment_valid! version_constraints_to_update = {} upload_failures = 0 upload_ok = 0 # Get a list of cookbooks and their versions from the server # to check for the existence of a cookbook's dependencies. @server_side_cookbooks = Chef::CookbookVersion.list_all_versions justify_width = @server_side_cookbooks.map {|name| name.size}.max.to_i + 2 if config[:all] cookbook_repo.load_cookbooks cbs = [] cookbook_repo.each do |cookbook_name, cookbook| cbs << cookbook cookbook.freeze_version if config[:freeze] version_constraints_to_update[cookbook_name] = cookbook.version end begin upload(cbs, justify_width) rescue Exceptions::CookbookFrozen ui.warn("Not updating version constraints for some cookbooks in the environment as the cookbook is frozen.") end ui.info("Uploaded all cookbooks.") else if @name_args.empty? show_usage ui.error("You must specify the --all flag or at least one cookbook name") exit 1 end cookbooks_to_upload.each do |cookbook_name, cookbook| cookbook.freeze_version if config[:freeze] begin upload([cookbook], justify_width) upload_ok += 1 version_constraints_to_update[cookbook_name] = cookbook.version rescue Exceptions::CookbookNotFoundInRepo => e upload_failures += 1 ui.error("Could not find cookbook #{cookbook_name} in your cookbook path, skipping it") Log.debug(e) upload_failures += 1 rescue Exceptions::CookbookFrozen ui.warn("Not updating version constraints for #{cookbook_name} in the environment as the cookbook is frozen.") upload_failures += 1 end end upload_failures += @name_args.length - @cookbooks_to_upload.length if upload_failures == 0 ui.info "Uploaded #{upload_ok} cookbook#{upload_ok > 1 ? "s" : ""}." elsif upload_failures > 0 && upload_ok > 0 ui.warn "Uploaded #{upload_ok} cookbook#{upload_ok > 1 ? "s" : ""} ok but #{upload_failures} " + "cookbook#{upload_failures > 1 ? "s" : ""} upload failed." elsif upload_failures > 0 && upload_ok == 0 ui.error "Failed to upload #{upload_failures} cookbook#{upload_failures > 1 ? "s" : ""}." exit 1 end end unless version_constraints_to_update.empty? update_version_constraints(version_constraints_to_update) if config[:environment] end end def cookbooks_to_upload @cookbooks_to_upload ||= if config[:all] cookbook_repo.load_cookbooks else upload_set = {} @name_args.each do |cookbook_name| begin if ! upload_set.has_key?(cookbook_name) upload_set[cookbook_name] = cookbook_repo[cookbook_name] if config[:depends] upload_set[cookbook_name].metadata.dependencies.each { |dep, ver| @name_args << dep } end end rescue Exceptions::CookbookNotFoundInRepo => e ui.error("Could not find cookbook #{cookbook_name} in your cookbook path, skipping it") Log.debug(e) end end upload_set end end def cookbook_repo @cookbook_loader ||= begin Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, config[:cookbook_path]) } Chef::CookbookLoader.new(config[:cookbook_path]) end end def update_version_constraints(new_version_constraints) new_version_constraints.each do |cookbook_name, version| environment.cookbook_versions[cookbook_name] = "= #{version}" end environment.save end def environment @environment ||= config[:environment] ? Environment.load(config[:environment]) : nil end def warn_about_cookbook_shadowing unless cookbook_repo.merged_cookbooks.empty? ui.warn "* " * 40 ui.warn(<<-WARNING) The cookbooks: #{cookbook_repo.merged_cookbooks.join(', ')} exist in multiple places in your cookbook_path. A composite version of these cookbooks has been compiled for uploading. #{ui.color('IMPORTANT:', :red, :bold)} In a future version of Chef, this behavior will be removed and you will no longer be able to have the same version of a cookbook in multiple places in your cookbook_path. WARNING ui.warn "The affected cookbooks are located:" ui.output ui.format_for_display(cookbook_repo.merged_cookbook_paths) ui.warn "* " * 40 end end private def assert_environment_valid! environment rescue Net::HTTPServerException => e if e.response.code.to_s == "404" ui.error "The environment #{config[:environment]} does not exist on the server, aborting." Log.debug(e) exit 1 else raise end end def upload(cookbooks, justify_width) cookbooks.each do |cb| ui.info("Uploading #{cb.name.to_s.ljust(justify_width + 10)} [#{cb.version}]") check_for_broken_links!(cb) check_for_dependencies!(cb) end Chef::CookbookUploader.new(cookbooks, config[:cookbook_path], :force => config[:force]).upload_cookbooks rescue Chef::Exceptions::CookbookFrozen => e ui.error e raise end def check_for_broken_links!(cookbook) # MUST!! dup the cookbook version object--it memoizes its # manifest object, but the manifest becomes invalid when you # regenerate the metadata broken_files = cookbook.dup.manifest_records_by_path.select do |path, info| info[CHECKSUM].nil? || info[CHECKSUM] !~ MATCH_CHECKSUM end unless broken_files.empty? broken_filenames = Array(broken_files).map {|path, info| path} ui.error "The cookbook #{cookbook.name} has one or more broken files" ui.error "This is probably caused by broken symlinks in the cookbook directory" ui.error "The broken file(s) are: #{broken_filenames.join(' ')}" exit 1 end end def check_for_dependencies!(cookbook) # for each dependency, check if the version is on the server, or # the version is in the cookbooks being uploaded. If not, exit and warn the user. cookbook.metadata.dependencies.each do |cookbook_name, version| unless check_server_side_cookbooks(cookbook_name, version) || check_uploading_cookbooks(cookbook_name, version) ui.error "Cookbook #{cookbook.name} depends on cookbook '#{cookbook_name}' version '#{version}'," ui.error "which is not currently being uploaded and cannot be found on the server." exit 1 end end end def check_server_side_cookbooks(cookbook_name, version) if @server_side_cookbooks[cookbook_name].nil? false else versions = @server_side_cookbooks[cookbook_name]['versions'].collect {|versions| versions["version"]} Log.debug "Versions of cookbook '#{cookbook_name}' returned by the server: #{versions.join(", ")}" @server_side_cookbooks[cookbook_name]["versions"].each do |versions_hash| if Chef::VersionConstraint.new(version).include?(versions_hash["version"]) Log.debug "Matched cookbook '#{cookbook_name}' with constraint '#{version}' to cookbook version '#{versions_hash['version']}' on the server" return true end end false end end def check_uploading_cookbooks(cookbook_name, version) if (! cookbooks_to_upload[cookbook_name].nil?) && Chef::VersionConstraint.new(version).include?(cookbooks_to_upload[cookbook_name].version) Log.debug "Matched cookbook '#{cookbook_name}' with constraint '#{version}' to a local cookbook." return true end false end end end end chef-11.8.2/lib/chef/knife/role_bulk_delete.rb0000644000004100000410000000344712254362222021144 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class RoleBulkDelete < Knife deps do require 'chef/role' require 'chef/json_compat' end banner "knife role bulk delete REGEX (options)" def run if @name_args.length < 1 ui.error("You must supply a regular expression to match the results against") exit 1 end all_roles = Chef::Role.list(true) matcher = /#{@name_args[0]}/ roles_to_delete = {} all_roles.each do |name, role| next unless name =~ matcher roles_to_delete[role.name] = role end if roles_to_delete.empty? ui.info "No roles match the expression /#{@name_args[0]}/" exit 0 end ui.msg("The following roles will be deleted:") ui.msg("") ui.msg(ui.list(roles_to_delete.keys.sort, :columns_down)) ui.msg("") ui.confirm("Are you sure you want to delete these roles") roles_to_delete.sort.each do |name, role| role.destroy ui.msg("Deleted role #{name}") end end end end end chef-11.8.2/lib/chef/knife/cookbook_test.rb0000644000004100000410000000553412254362222020510 0ustar www-datawww-data# # # Author:: Adam Jacob () # Author:: Matthew Kent () # Copyright:: Copyright (c) 2009 Opscode, Inc. # Copyright:: Copyright (c) 2010 Matthew Kent # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class CookbookTest < Knife deps do require 'chef/cookbook_loader' require 'chef/cookbook/syntax_check' end banner "knife cookbook test [COOKBOOKS...] (options)" option :cookbook_path, :short => "-o PATH:PATH", :long => "--cookbook-path PATH:PATH", :description => "A colon-separated path to look for cookbooks in", :proc => lambda { |o| o.split(":") } option :all, :short => "-a", :long => "--all", :description => "Test all cookbooks, rather than just a single cookbook" def run config[:cookbook_path] ||= Chef::Config[:cookbook_path] checked_a_cookbook = false if config[:all] cl = cookbook_loader cl.load_cookbooks cl.each do |key, cookbook| checked_a_cookbook = true test_cookbook(key) end else @name_args.each do |cb| ui.info "checking #{cb}" next unless cookbook_loader.cookbook_exists?(cb) checked_a_cookbook = true test_cookbook(cb) end end unless checked_a_cookbook ui.warn("No cookbooks to test in #{Array(config[:cookbook_path]).join(',')} - is your cookbook path misconfigured?") end end def test_cookbook(cookbook) ui.info("Running syntax check on #{cookbook}") Array(config[:cookbook_path]).reverse.each do |path| syntax_checker = Chef::Cookbook::SyntaxCheck.for_cookbook(cookbook, path) test_ruby(syntax_checker) test_templates(syntax_checker) end end def test_ruby(syntax_checker) ui.info("Validating ruby files") exit(1) unless syntax_checker.validate_ruby_files end def test_templates(syntax_checker) ui.info("Validating templates") exit(1) unless syntax_checker.validate_templates end def cookbook_loader @cookbook_loader ||= Chef::CookbookLoader.new(config[:cookbook_path]) end end end end chef-11.8.2/lib/chef/knife/node_from_file.rb0000644000004100000410000000240612254362222020605 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class NodeFromFile < Knife deps do require 'chef/node' require 'chef/json_compat' require 'chef/knife/core/object_loader' end banner "knife node from file FILE (options)" def loader @loader ||= Knife::Core::ObjectLoader.new(Chef::Node, ui) end def run updated = loader.load_from('nodes', @name_args[0]) updated.save output(format_for_display(updated)) if config[:print_after] ui.info("Updated Node #{updated.name}!") end end end end chef-11.8.2/lib/chef/knife/help_topics.rb0000644000004100000410000000112312254362222020142 0ustar www-datawww-data# Do not edit this file by hand # This file is autogenerated by the docs:list rake task from the available manpages HELP_TOPICS = ["chef-shell", "knife-bootstrap", "knife-client", "knife-configure", "knife-cookbook-site", "knife-cookbook", "knife-data-bag", "knife-delete", "knife-deps", "knife-diff", "knife-download", "knife-edit", "knife-environment", "knife-exec", "knife-index-rebuild", "knife-list", "knife-node", "knife-raw", "knife-recipe-list", "knife-role", "knife-search", "knife-show", "knife-ssh", "knife-status", "knife-tag", "knife-upload", "knife-user", "knife-xargs", "knife"] chef-11.8.2/lib/chef/knife/cookbook_site_unshare.rb0000644000004100000410000000317712254362222022223 0ustar www-datawww-data# # Author:: Stephen Delano () # Author:: Tim Hinderliter () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class CookbookSiteUnshare < Knife deps do require 'chef/json_compat' end banner "knife cookbook site unshare COOKBOOK" category "cookbook site" def run @cookbook_name = @name_args[0] if @cookbook_name.nil? show_usage ui.fatal "You must provide the name of the cookbook to unshare" exit 1 end confirm "Do you really want to unshare the cookbook #{@cookbook_name}" begin rest.delete_rest "http://cookbooks.opscode.com/api/v1/cookbooks/#{@name_args[0]}" rescue Net::HTTPServerException => e raise e unless e.message =~ /Forbidden/ ui.error "Forbidden: You must be the maintainer of #{@cookbook_name} to unshare it." exit 1 end ui.info "Unshared cookbook #{@cookbook_name}" end end end end chef-11.8.2/lib/chef/knife/role_delete.rb0000644000004100000410000000217612254362222020125 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class RoleDelete < Knife deps do require 'chef/role' require 'chef/json_compat' end banner "knife role delete ROLE (options)" def run @role_name = @name_args[0] if @role_name.nil? show_usage ui.fatal("You must specify a role name") exit 1 end delete_object(Chef::Role, @role_name) end end end end chef-11.8.2/lib/chef/knife/core/0000755000004100000410000000000012254362222016237 5ustar www-datawww-datachef-11.8.2/lib/chef/knife/core/node_presenter.rb0000644000004100000410000001051412254362222021601 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife/core/text_formatter' require 'chef/knife/core/generic_presenter' class Chef class Knife module Core # This module may be included into a knife subcommand class to automatically # add configuration options used by the NodePresenter module NodeFormattingOptions # :nodoc: # Would prefer to do this in a rational way, but can't be done b/c of # Mixlib::CLI's design :( def self.included(includer) includer.class_eval do option :medium_output, :short => '-m', :long => '--medium', :boolean => true, :default => false, :description => 'Include normal attributes in the output' option :long_output, :short => '-l', :long => '--long', :boolean => true, :default => false, :description => 'Include all attributes in the output' end end end #==Chef::Knife::Core::NodePresenter # A customized presenter for Chef::Node objects. Supports variable-length # output formats for displaying node data class NodePresenter < GenericPresenter def format(data) if parse_format_option == :json summarize_json(data) else super end end def summarize_json(data) if data.kind_of?(Chef::Node) node = data result = {} result["name"] = node.name result["chef_environment"] = node.chef_environment result["run_list"] = node.run_list result["normal"] = node.normal_attrs if config[:long_output] result["default"] = node.default_attrs result["override"] = node.override_attrs result["automatic"] = node.automatic_attrs end Chef::JSONCompat.to_json_pretty(result) else Chef::JSONCompat.to_json_pretty(data) end end # Converts a Chef::Node object to a string suitable for output to a # terminal. If config[:medium_output] or config[:long_output] are set # the volume of output is adjusted accordingly. Uses colors if enabled # in the ui object. def summarize(data) if data.kind_of?(Chef::Node) node = data # special case ec2 with their split horizon whatsis. ip = (node[:ec2] && node[:ec2][:public_ipv4]) || node[:ipaddress] summarized=<<-SUMMARY #{ui.color('Node Name:', :bold)} #{ui.color(node.name, :bold)} #{key('Environment:')} #{node.chef_environment} #{key('FQDN:')} #{node[:fqdn]} #{key('IP:')} #{ip} #{key('Run List:')} #{node.run_list} #{key('Roles:')} #{Array(node[:roles]).join(', ')} #{key('Recipes:')} #{Array(node[:recipes]).join(', ')} #{key('Platform:')} #{node[:platform]} #{node[:platform_version]} #{key('Tags:')} #{Array(node[:tags]).join(', ')} SUMMARY if config[:medium_output] || config[:long_output] summarized +=<<-MORE #{key('Attributes:')} #{text_format(node.normal_attrs)} MORE end if config[:long_output] summarized +=<<-MOST #{key('Default Attributes:')} #{text_format(node.default_attrs)} #{key('Override Attributes:')} #{text_format(node.override_attrs)} #{key('Automatic Attributes (Ohai Data):')} #{text_format(node.automatic_attrs)} MOST end summarized else super end end def key(key_text) ui.color(key_text, :cyan) end end end end end chef-11.8.2/lib/chef/knife/core/generic_presenter.rb0000644000004100000410000001656412254362222022303 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife/core/text_formatter' class Chef class Knife module Core # Allows includer knife commands to return multiple attributes # @brief knife node show NAME -a ATTR1 -a ATTR2 module MultiAttributeReturnOption # :nodoc: def self.included(includer) includer.class_eval do @attrs_to_show = [] option :attribute, :short => "-a ATTR1 [-a ATTR2]", :long => "--attribute ATTR1 [--attribute ATTR2] ", :proc => lambda {|val| @attrs_to_show << val}, :description => "Show one or more attributes" end end end #==Chef::Knife::Core::GenericPresenter # The base presenter class for displaying structured data in knife commands. # This is not an abstract base class, and it is suitable for displaying # most kinds of objects that knife needs to display. class GenericPresenter attr_reader :ui attr_reader :config # Instaniates a new GenericPresenter. This is generally handled by the # Chef::Knife::UI object, though you need to match the signature of this # method if you intend to use your own presenter instead. def initialize(ui, config) @ui, @config = ui, config end # Is the selected output format a data interchange format? # Returns true if the selected output format is json or yaml, false # otherwise. Knife search uses this to adjust its data output so as not # to produce invalid JSON output. def interchange? case parse_format_option when :json, :yaml true else false end end # Returns a String representation of +data+ that is suitable for output # to a terminal or perhaps for data interchange with another program. # The representation of the +data+ depends on the value of the # `config[:format]` setting. def format(data) case parse_format_option when :summary summarize(data) when :text text_format(data) when :json Chef::JSONCompat.to_json_pretty(data) when :yaml require 'yaml' YAML::dump(data) when :pp require 'stringio' # If you were looking for some attribute and there is only one match # just dump the attribute value if config[:attribute] and data.length == 1 data.values[0] else out = StringIO.new PP.pp(data, out) out.string end end end # Converts the user-supplied value of `config[:format]` to a Symbol # representing the desired output format. # ===Returns # returns one of :summary, :text, :json, :yaml, or :pp # ===Raises # Raises an ArgumentError if the desired output format could not be # determined from the value of `config[:format]` def parse_format_option case config[:format] when "summary", /^s/, nil :summary when "text", /^t/ :text when "json", /^j/ :json when "yaml", /^y/ :yaml when "pp", /^p/ :pp else raise ArgumentError, "Unknown output format #{config[:format]}" end end # Summarize the data. Defaults to text format output, # which may not be very summary-like def summarize(data) text_format(data) end # Converts the +data+ to a String in the text format. Uses # Chef::Knife::Core::TextFormatter def text_format(data) TextFormatter.new(data, ui).formatted_data end def format_list_for_display(list) config[:with_uri] ? list : list.keys.sort { |a,b| a <=> b } end def format_for_display(data) if formatting_subset_of_data? format_data_subset_for_display(data) elsif config[:id_only] name_or_id_for(data) elsif config[:environment] && data.respond_to?(:chef_environment) {"chef_environment" => data.chef_environment} else data end end def format_data_subset_for_display(data) subset = if config[:attribute] result = {} Array(config[:attribute]).each do |nested_value_spec| nested_value = extract_nested_value(data, nested_value_spec) result[nested_value_spec] = nested_value end result elsif config[:run_list] run_list = data.run_list.run_list { "run_list" => run_list } else raise ArgumentError, "format_data_subset_for_display requires attribute, run_list, or id_only config option to be set" end {name_or_id_for(data) => subset } end def name_or_id_for(data) data.respond_to?(:name) ? data.name : data["id"] end def formatting_subset_of_data? config[:attribute] || config[:run_list] end def extract_nested_value(data, nested_value_spec) nested_value_spec.split(".").each do |attr| if data.nil? nil # don't get no method error on nil elsif data.respond_to?(attr.to_sym) data = data.send(attr.to_sym) elsif data.respond_to?(:[]) data = data[attr] else data = begin data.send(attr.to_sym) rescue NoMethodError nil end end end ( !data.kind_of?(Array) && data.respond_to?(:to_hash) ) ? data.to_hash : data end def format_cookbook_list_for_display(item) if config[:with_uri] item.inject({}) do |collected, (cookbook, versions)| collected[cookbook] = Hash.new versions['versions'].each do |ver| collected[cookbook][ver['version']] = ver['url'] end collected end else versions_by_cookbook = item.inject({}) do |collected, ( cookbook, versions )| collected[cookbook] = versions["versions"].map {|v| v['version']} collected end key_length = versions_by_cookbook.empty? ? 0 : versions_by_cookbook.keys.map {|name| name.size }.max + 2 versions_by_cookbook.sort.map do |cookbook, versions| "#{cookbook.ljust(key_length)} #{versions.join(' ')}" end end end end end end end chef-11.8.2/lib/chef/knife/core/bootstrap_context.rb0000644000004100000410000000743612254362222022357 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/run_list' class Chef class Knife module Core # Instances of BootstrapContext are the context objects (i.e., +self+) for # bootstrap templates. For backwards compatability, they +must+ set the # following instance variables: # * @config - a hash of knife's config values # * @run_list - the run list for the node to boostrap # class BootstrapContext def initialize(config, run_list, chef_config) @config = config @run_list = run_list @chef_config = chef_config end def bootstrap_version_string if @config[:prerelease] "--prerelease" else "--version #{chef_version}" end end def bootstrap_environment @chef_config[:environment] || '_default' end def validation_key IO.read(File.expand_path(@chef_config[:validation_key])) end def encrypted_data_bag_secret knife_config[:secret] || begin if knife_config[:secret_file] && File.exist?(knife_config[:secret_file]) IO.read(File.expand_path(knife_config[:secret_file])) elsif @chef_config[:encrypted_data_bag_secret] && File.exist?(@chef_config[:encrypted_data_bag_secret]) IO.read(File.expand_path(@chef_config[:encrypted_data_bag_secret])) end end end def config_content client_rb = <<-CONFIG log_level :auto log_location STDOUT chef_server_url "#{@chef_config[:chef_server_url]}" validation_client_name "#{@chef_config[:validation_client_name]}" CONFIG if @config[:chef_node_name] client_rb << %Q{node_name "#{@config[:chef_node_name]}"\n} else client_rb << "# Using default node name (fqdn)\n" end if knife_config[:bootstrap_proxy] client_rb << %Q{http_proxy "#{knife_config[:bootstrap_proxy]}"\n} client_rb << %Q{https_proxy "#{knife_config[:bootstrap_proxy]}"\n} end if knife_config[:bootstrap_no_proxy] client_rb << %Q{no_proxy "#{knife_config[:bootstrap_no_proxy]}"\n} end if encrypted_data_bag_secret client_rb << %Q{encrypted_data_bag_secret "/etc/chef/encrypted_data_bag_secret"\n} end client_rb end def start_chef # If the user doesn't have a client path configure, let bash use the PATH for what it was designed for client_path = @chef_config[:chef_client_path] || 'chef-client' s = "#{client_path} -j /etc/chef/first-boot.json" s << " -E #{bootstrap_environment}" if chef_version.to_f != 0.9 # only use the -E option on Chef 0.10+ s end def knife_config @chef_config.key?(:knife) ? @chef_config[:knife] : {} end def chef_version knife_config[:bootstrap_version] || Chef::VERSION end def first_boot (@config[:first_boot_attributes] || {}).merge(:run_list => @run_list) end end end end end chef-11.8.2/lib/chef/knife/core/object_loader.rb0000644000004100000410000000650012254362222021361 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Knife module Core class ObjectLoader attr_reader :ui attr_reader :klass class ObjectType FILE = 1 FOLDER = 2 end def initialize(klass, ui) @klass = klass @ui = ui end def load_from(repo_location, *components) unless object_file = find_file(repo_location, *components) ui.error "Could not find or open file '#{components.last}' in current directory or in '#{repo_location}/#{components.join('/')}'" exit 1 end object_from_file(object_file) end # When someone makes this awesome, please update the above error message. def find_file(repo_location, *components) if file_exists_and_is_readable?(File.expand_path( components.last )) File.expand_path( components.last ) else relative_path = File.join(Dir.pwd, repo_location, *components) if file_exists_and_is_readable?(relative_path) relative_path else nil end end end # Find all objects in the given location # If the object type is File it will look for all *.{json,rb} # files, otherwise it will lookup for folders only (useful for # data_bags) # # @param [String] path - base look up location # # @return [Array] basenames of the found objects # # @api public def find_all_objects(path) path = File.join(path, '*') path << '.{json,rb}' objects = Dir.glob(File.expand_path(path)) objects.map { |o| File.basename(o) } end def find_all_object_dirs(path) path = File.join(path, '*') objects = Dir.glob(File.expand_path(path)) objects.delete_if { |o| !File.directory?(o) } objects.map { |o| File.basename(o) } end def object_from_file(filename) case filename when /\.(js|json)$/ r = Yajl::Parser.parse(IO.read(filename)) # Chef::DataBagItem doesn't work well with the json_create method if @klass == Chef::DataBagItem r else @klass.json_create(r) end when /\.rb$/ r = klass.new r.from_file(filename) r else ui.fatal("File must end in .js, .json, or .rb") exit 30 end end def file_exists_and_is_readable?(file) File.exists?(file) && File.readable?(file) end end end end end chef-11.8.2/lib/chef/knife/core/node_editor.rb0000644000004100000410000000670112254362222021063 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/json_compat' require 'chef/node' require 'tempfile' class Chef class Knife class NodeEditor attr_reader :node attr_reader :ui attr_reader :config def initialize(node, ui, config) @node, @ui, @config = node, ui, config end def edit_node abort "You specified the --disable_editing option, nothing to edit" if config[:disable_editing] assert_editor_set! updated_node_data = @ui.edit_data(view) apply_updates(updated_node_data) @updated_node end def updated? pristine_copy = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(node), :create_additions => false) updated_copy = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(@updated_node), :create_additions => false) unless pristine_copy == updated_copy updated_properties = %w{name normal chef_environment run_list default override automatic}.reject do |key| pristine_copy[key] == updated_copy[key] end end ( pristine_copy != updated_copy ) && updated_properties end private def view result = {} result["name"] = node.name result["chef_environment"] = node.chef_environment result["normal"] = node.normal_attrs result["run_list"] = node.run_list if config[:all_attributes] result["default"] = node.default_attrs result["override"] = node.override_attrs result["automatic"] = node.automatic_attrs end result end def apply_updates(updated_data) if node.name and node.name != updated_data["name"] ui.warn "Changing the name of a node results in a new node being created, #{node.name} will not be modified or removed." confirm = ui.confirm "Proceed with creation of new node" end @updated_node = Node.new.tap do |n| n.name( updated_data["name"] ) n.chef_environment( updated_data["chef_environment"] ) n.run_list( updated_data["run_list"]) n.normal_attrs = updated_data["normal"] if config[:all_attributes] n.default_attrs = updated_data["default"] n.override_attrs = updated_data["override"] n.automatic_attrs = updated_data["automatic"] else n.default_attrs = node.default_attrs n.override_attrs = node.override_attrs n.automatic_attrs = node.automatic_attrs end end end def abort(message) ui.error(message) exit 1 end def assert_editor_set! unless config[:editor] abort "You must set your EDITOR environment variable or configure your editor via knife.rb" end end end end end chef-11.8.2/lib/chef/knife/core/text_formatter.rb0000644000004100000410000000524612254362222021642 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Knife module Core class TextFormatter attr_reader :data attr_reader :ui def initialize(data, ui) @ui = ui @data = if data.respond_to?(:display_hash) data.display_hash elsif data.kind_of?(Array) data elsif data.respond_to?(:to_hash) data.to_hash else data end end def formatted_data @formatted_data ||= text_format(data) end def text_format(data) buffer = '' if data.respond_to?(:keys) justify_width = data.keys.map {|k| k.to_s.size }.max.to_i + 1 data.sort.each do |key, value| # key: ['value'] should be printed as key: value if value.kind_of?(Array) && value.size == 1 && is_singleton(value[0]) value = value[0] end if is_singleton(value) # Strings are printed as key: value. justified_key = ui.color("#{key}:".ljust(justify_width), :cyan) buffer << "#{justified_key} #{value}\n" else # Arrays and hashes get indented on their own lines. buffer << ui.color("#{key}:\n", :cyan) lines = text_format(value).split("\n") lines.each { |line| buffer << " #{line}\n" } end end elsif data.kind_of?(Array) data.each_index do |index| item = data[index] buffer << text_format(data[index]) # Separate items with newlines if it's an array of hashes or an # array of arrays buffer << "\n" if !is_singleton(data[index]) && index != data.size-1 end else buffer << "#{data}\n" end buffer end def is_singleton(value) !(value.kind_of?(Array) || value.respond_to?(:keys)) end end end end end chef-11.8.2/lib/chef/knife/core/subcommand_loader.rb0000644000004100000410000001125612254362222022247 0ustar www-datawww-data# Author:: Christopher Brown () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009, 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/version' class Chef class Knife class SubcommandLoader attr_reader :chef_config_dir attr_reader :env def initialize(chef_config_dir, env=ENV) @chef_config_dir, @env = chef_config_dir, env @forced_activate = {} end # Load all the sub-commands def load_commands subcommand_files.each { |subcommand| Kernel.load subcommand } true end # Returns an Array of paths to knife commands located in chef_config_dir/plugins/knife/ # and ~/.chef/plugins/knife/ def site_subcommands user_specific_files = [] if chef_config_dir user_specific_files.concat Dir.glob(File.expand_path("plugins/knife/*.rb", chef_config_dir)) end # finally search ~/.chef/plugins/knife/*.rb user_specific_files.concat Dir.glob(File.join(env['HOME'], '.chef', 'plugins', 'knife', '*.rb')) if env['HOME'] user_specific_files end # Returns a Hash of paths to knife commands built-in to chef, or installed via gem. # If rubygems is not installed, falls back to globbing the knife directory. # The Hash is of the form {"relative/path" => "/absolute/path"} #-- # Note: the "right" way to load the plugins is to require the relative path, i.e., # require 'chef/knife/command' # but we're getting frustrated by bugs at every turn, and it's slow besides. So # subcommand loader has been modified to load the plugins by using Kernel.load # with the absolute path. def gem_and_builtin_subcommands # search all gems for chef/knife/*.rb require 'rubygems' find_subcommands_via_rubygems rescue LoadError find_subcommands_via_dirglob end def subcommand_files @subcommand_files ||= (gem_and_builtin_subcommands.values + site_subcommands).flatten.uniq end def find_subcommands_via_dirglob # The "require paths" of the core knife subcommands bundled with chef files = Dir[File.expand_path('../../../knife/*.rb', __FILE__)] subcommand_files = {} files.each do |knife_file| rel_path = knife_file[/#{CHEF_ROOT}#{Regexp.escape(File::SEPARATOR)}(.*)\.rb/,1] subcommand_files[rel_path] = knife_file end subcommand_files end def find_subcommands_via_rubygems files = find_files_latest_gems 'chef/knife/*.rb' subcommand_files = {} files.each do |file| rel_path = file[/(#{Regexp.escape File.join('chef', 'knife', '')}.*)\.rb/, 1] subcommand_files[rel_path] = file end subcommand_files.merge(find_subcommands_via_dirglob) end private def find_files_latest_gems(glob, check_load_path=true) files = [] if check_load_path files = $LOAD_PATH.map { |load_path| Dir["#{File.expand_path glob, load_path}#{Gem.suffix_pattern}"] }.flatten.select { |file| File.file? file.untaint } end gem_files = latest_gem_specs.map do |spec| # Gem::Specification#matches_for_glob wasn't added until RubyGems 1.8 if spec.respond_to? :matches_for_glob spec.matches_for_glob("#{glob}#{Gem.suffix_pattern}") else check_spec_for_glob(spec, glob) end end.flatten files.concat gem_files files.uniq! if check_load_path return files end def latest_gem_specs @latest_gem_specs ||= if Gem::Specification.respond_to? :latest_specs Gem::Specification.latest_specs else Gem.source_index.latest_specs end end def check_spec_for_glob(spec, glob) dirs = if spec.require_paths.size > 1 then "{#{spec.require_paths.join(',')}}" else spec.require_paths.first end glob = File.join("#{spec.full_gem_path}/#{dirs}", glob) Dir[glob].map { |f| f.untaint } end end end end chef-11.8.2/lib/chef/knife/core/ui.rb0000644000004100000410000001520312254362222017202 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Brown () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009, 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'forwardable' require 'chef/platform/query_helpers' require 'chef/knife/core/generic_presenter' require 'tempfile' class Chef class Knife #==Chef::Knife::UI # The User Interaction class used by knife. class UI extend Forwardable attr_reader :stdout attr_reader :stderr attr_reader :stdin attr_reader :config attr_reader :presenter def_delegator :@presenter, :format_list_for_display def_delegator :@presenter, :format_for_display def_delegator :@presenter, :format_cookbook_list_for_display def initialize(stdout, stderr, stdin, config) @stdout, @stderr, @stdin, @config = stdout, stderr, stdin, config @presenter = Chef::Knife::Core::GenericPresenter.new(self, config) end # Creates a new +presenter_class+ object and uses it to format structured # data for display. By default, a Chef::Knife::Core::GenericPresenter # object is used. def use_presenter(presenter_class) @presenter = presenter_class.new(self, config) end def highline @highline ||= begin require 'highline' HighLine.new end end # Prints a message to stdout. Aliased as +info+ for compatibility with # the logger API. def msg(message) begin stdout.puts message rescue Errno::EPIPE => e raise e if @config[:verbosity] >= 2 exit 0 end end alias :info :msg # Prints a msg to stderr. Used for warn, error, and fatal. def err(message) begin stderr.puts message rescue Errno::EPIPE => e raise e if @config[:verbosity] >= 2 exit 0 end end # Print a warning message def warn(message) err("#{color('WARNING:', :yellow, :bold)} #{message}") end # Print an error message def error(message) err("#{color('ERROR:', :red, :bold)} #{message}") end # Print a message describing a fatal error. def fatal(message) err("#{color('FATAL:', :red, :bold)} #{message}") end def color(string, *colors) if color? highline.color(string, *colors) else string end end # Should colored output be used? For output to a terminal, this is # determined by the value of `config[:color]`. When output is not to a # terminal, colored output is never used def color? Chef::Config[:color] && stdout.tty? && !Chef::Platform.windows? end def ask(*args, &block) highline.ask(*args, &block) end def list(*args) highline.list(*args) end # Formats +data+ using the configured presenter and outputs the result # via +msg+. Formatting can be customized by configuring a different # presenter. See +use_presenter+ def output(data) msg @presenter.format(data) end # Determines if the output format is a data interchange format, i.e., # JSON or YAML def interchange? @presenter.interchange? end def ask_question(question, opts={}) question = question + "[#{opts[:default]}] " if opts[:default] if opts[:default] and config[:defaults] opts[:default] else stdout.print question a = stdin.readline.strip if opts[:default] a.empty? ? opts[:default] : a else a end end end def pretty_print(data) begin stdout.puts data rescue Errno::EPIPE => e raise e if @config[:verbosity] >= 2 exit 0 end end def edit_data(data, parse_output=true) output = Chef::JSONCompat.to_json_pretty(data) if (!config[:disable_editing]) Tempfile.open([ 'knife-edit-', '.json' ]) do |tf| tf.sync = true tf.puts output tf.close raise "Please set EDITOR environment variable" unless system("#{config[:editor]} #{tf.path}") output = IO.read(tf.path) end end parse_output ? Chef::JSONCompat.from_json(output) : output end def edit_object(klass, name) object = klass.load(name) output = edit_data(object) # Only make the save if the user changed the object. # # Output JSON for the original (object) and edited (output), then parse # them without reconstituting the objects into real classes # (create_additions=false). Then, compare the resulting simple objects, # which will be Array/Hash/String/etc. # # We wouldn't have to do these shenanigans if all the editable objects # implemented to_hash, or if to_json against a hash returned a string # with stable key order. object_parsed_again = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(object), :create_additions => false) output_parsed_again = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json(output), :create_additions => false) if object_parsed_again != output_parsed_again output.save self.msg("Saved #{output}") else self.msg("Object unchanged, not saving") end output(format_for_display(object)) if config[:print_after] end def confirm(question, append_instructions=true) return true if config[:yes] stdout.print question stdout.print "? (Y/N) " if append_instructions answer = stdin.readline answer.chomp! case answer when "Y", "y" true when "N", "n" self.msg("You said no, so I'm done here.") exit 3 else self.msg("I have no idea what to do with #{answer}") self.msg("Just say Y or N, please.") confirm(question) end end end end end chef-11.8.2/lib/chef/knife/core/cookbook_scm_repo.rb0000644000004100000410000001175712254362222022274 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/mixin/shell_out' class Chef class Knife class CookbookSCMRepo DIRTY_REPO = /^[\s]+M/ include Chef::Mixin::ShellOut attr_reader :repo_path attr_reader :default_branch attr_reader :use_current_branch attr_reader :ui def initialize(repo_path, ui, opts={}) @repo_path = repo_path @ui = ui @default_branch = 'master' @use_current_branch = false apply_opts(opts) end def sanity_check unless ::File.directory?(repo_path) ui.error("The cookbook repo path #{repo_path} does not exist or is not a directory") exit 1 end unless git_repo?(repo_path) ui.error "The cookbook repo #{repo_path} is not a git repository." ui.info("Use `git init` to initialize a git repo") exit 1 end if use_current_branch @default_branch = get_current_branch() end unless branch_exists?(default_branch) ui.error "The default branch '#{default_branch}' does not exist" ui.info "If this is a new git repo, make sure you have at least one commit before installing cookbooks" exit 1 end cmd = git('status --porcelain') if cmd.stdout =~ DIRTY_REPO ui.error "You have uncommitted changes to your cookbook repo (#{repo_path}):" ui.msg cmd.stdout ui.info "Commit or stash your changes before importing cookbooks" exit 1 end # TODO: any untracked files in the cookbook directory will get nuked later # make this an error condition also. true end def reset_to_default_state ui.info("Checking out the #{default_branch} branch.") git("checkout #{default_branch}") end def prepare_to_import(cookbook_name) branch = "chef-vendor-#{cookbook_name}" if branch_exists?(branch) ui.info("Pristine copy branch (#{branch}) exists, switching to it.") git("checkout #{branch}") else ui.info("Creating pristine copy branch #{branch}") git("checkout -b #{branch}") end end def finalize_updates_to(cookbook_name, version) if update_count = updated?(cookbook_name) ui.info "#{update_count} files updated, committing changes" git("add #{cookbook_name}") git("commit -m \"Import #{cookbook_name} version #{version}\" -- #{cookbook_name}") ui.info("Creating tag cookbook-site-imported-#{cookbook_name}-#{version}") git("tag -f cookbook-site-imported-#{cookbook_name}-#{version}") true else ui.info("No changes made to #{cookbook_name}") false end end def merge_updates_from(cookbook_name, version) branch = "chef-vendor-#{cookbook_name}" Dir.chdir(repo_path) do if system("git merge #{branch}") ui.info("Cookbook #{cookbook_name} version #{version} successfully installed") else ui.error("You have merge conflicts - please resolve manually") ui.info("Merge status (cd #{repo_path}; git status):") system("git status") exit 3 end end end def updated?(cookbook_name) update_count = git("status --porcelain -- #{cookbook_name}").stdout.strip.lines.count update_count == 0 ? nil : update_count end def branch_exists?(branch_name) git("branch --no-color").stdout.lines.any? {|l| l =~ /\s#{Regexp.escape(branch_name)}(?:\s|$)/ } end def get_current_branch() ref = git("symbolic-ref HEAD").stdout ref.chomp.split('/')[2] end private def git_repo?(directory) if File.directory?(File.join(directory, '.git')) return true elsif File.dirname(directory) == directory return false else git_repo?(File.dirname(directory)) end end def apply_opts(opts) opts.each do |option, value| case option.to_s when 'default_branch' @default_branch = value when 'use_current_branch' @use_current_branch = value end end end def git(command) shell_out!("git #{command}", :cwd => repo_path) end end end end chef-11.8.2/lib/chef/knife/bootstrap.rb0000644000004100000410000002357212254362222017662 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' require 'erubis' class Chef class Knife class Bootstrap < Knife deps do require 'chef/knife/core/bootstrap_context' require 'chef/json_compat' require 'tempfile' require 'highline' require 'net/ssh' require 'net/ssh/multi' require 'chef/knife/ssh' Chef::Knife::Ssh.load_deps end banner "knife bootstrap FQDN (options)" option :ssh_user, :short => "-x USERNAME", :long => "--ssh-user USERNAME", :description => "The ssh username", :default => "root" option :ssh_password, :short => "-P PASSWORD", :long => "--ssh-password PASSWORD", :description => "The ssh password" option :ssh_port, :short => "-p PORT", :long => "--ssh-port PORT", :description => "The ssh port", :proc => Proc.new { |key| Chef::Config[:knife][:ssh_port] = key } option :ssh_gateway, :short => "-G GATEWAY", :long => "--ssh-gateway GATEWAY", :description => "The ssh gateway", :proc => Proc.new { |key| Chef::Config[:knife][:ssh_gateway] = key } option :forward_agent, :short => "-A", :long => "--forward-agent", :description => "Enable SSH agent forwarding", :boolean => true option :identity_file, :short => "-i IDENTITY_FILE", :long => "--identity-file IDENTITY_FILE", :description => "The SSH identity file used for authentication" option :chef_node_name, :short => "-N NAME", :long => "--node-name NAME", :description => "The Chef node name for your new node" option :prerelease, :long => "--prerelease", :description => "Install the pre-release chef gems" option :bootstrap_version, :long => "--bootstrap-version VERSION", :description => "The version of Chef to install", :proc => lambda { |v| Chef::Config[:knife][:bootstrap_version] = v } option :bootstrap_proxy, :long => "--bootstrap-proxy PROXY_URL", :description => "The proxy server for the node being bootstrapped", :proc => Proc.new { |p| Chef::Config[:knife][:bootstrap_proxy] = p } option :bootstrap_no_proxy, :long => "--bootstrap-no-proxy [NO_PROXY_URL|NO_PROXY_IP]", :description => "Do not proxy locations for the node being bootstrapped", :proc => Proc.new { |np| Chef::Config[:knife][:bootstrap_no_proxy] = np } option :distro, :short => "-d DISTRO", :long => "--distro DISTRO", :description => "Bootstrap a distro using a template", :default => "chef-full" option :use_sudo, :long => "--sudo", :description => "Execute the bootstrap via sudo", :boolean => true option :use_sudo_password, :long => "--use-sudo-password", :description => "Execute the bootstrap via sudo with password", :boolean => false option :template_file, :long => "--template-file TEMPLATE", :description => "Full path to location of template to use", :default => false option :run_list, :short => "-r RUN_LIST", :long => "--run-list RUN_LIST", :description => "Comma separated list of roles/recipes to apply", :proc => lambda { |o| o.split(/[\s,]+/) }, :default => [] option :first_boot_attributes, :short => "-j JSON_ATTRIBS", :long => "--json-attributes", :description => "A JSON string to be added to the first run of chef-client", :proc => lambda { |o| JSON.parse(o) }, :default => {} option :host_key_verify, :long => "--[no-]host-key-verify", :description => "Verify host key, enabled by default.", :boolean => true, :default => true option :hint, :long => "--hint HINT_NAME[=HINT_FILE]", :description => "Specify Ohai Hint to be set on the bootstrap target. Use multiple --hint options to specify multiple hints.", :proc => Proc.new { |h| Chef::Config[:knife][:hints] ||= Hash.new name, path = h.split("=") Chef::Config[:knife][:hints][name] = path ? JSON.parse(::File.read(path)) : Hash.new } option :secret, :short => "-s SECRET", :long => "--secret ", :description => "The secret key to use to encrypt data bag item values", :proc => Proc.new { |s| Chef::Config[:knife][:secret] = s } option :secret_file, :long => "--secret-file SECRET_FILE", :description => "A file containing the secret key to use to encrypt data bag item values", :proc => Proc.new { |sf| Chef::Config[:knife][:secret_file] = sf } def find_template(template=nil) # Are we bootstrapping using an already shipped template? if config[:template_file] bootstrap_files = config[:template_file] else bootstrap_files = [] bootstrap_files << File.join(File.dirname(__FILE__), 'bootstrap', "#{config[:distro]}.erb") bootstrap_files << File.join(Knife.chef_config_dir, "bootstrap", "#{config[:distro]}.erb") if Knife.chef_config_dir bootstrap_files << File.join(ENV['HOME'], '.chef', 'bootstrap', "#{config[:distro]}.erb") if ENV['HOME'] bootstrap_files << Gem.find_files(File.join("chef","knife","bootstrap","#{config[:distro]}.erb")) bootstrap_files.flatten! end template = Array(bootstrap_files).find do |bootstrap_template| Chef::Log.debug("Looking for bootstrap template in #{File.dirname(bootstrap_template)}") File.exists?(bootstrap_template) end unless template ui.info("Can not find bootstrap definition for #{config[:distro]}") raise Errno::ENOENT end Chef::Log.debug("Found bootstrap template in #{File.dirname(template)}") template end def render_template(template=nil) context = Knife::Core::BootstrapContext.new(config, config[:run_list], Chef::Config) Erubis::Eruby.new(template).evaluate(context) end def read_template IO.read(@template_file).chomp end def run validate_name_args! warn_chef_config_secret_key @template_file = find_template(config[:bootstrap_template]) @node_name = Array(@name_args).first # back compat--templates may use this setting: config[:server_name] = @node_name $stdout.sync = true ui.info("Bootstrapping Chef on #{ui.color(@node_name, :bold)}") begin knife_ssh.run rescue Net::SSH::AuthenticationFailed unless config[:ssh_password] ui.info("Failed to authenticate #{config[:ssh_user]} - trying password auth") knife_ssh_with_password_auth.run end end end def validate_name_args! if Array(@name_args).first.nil? ui.error("Must pass an FQDN or ip to bootstrap") exit 1 end end def server_name Array(@name_args).first end def knife_ssh ssh = Chef::Knife::Ssh.new ssh.ui = ui ssh.name_args = [ server_name, ssh_command ] ssh.config[:ssh_user] = Chef::Config[:knife][:ssh_user] || config[:ssh_user] ssh.config[:ssh_password] = config[:ssh_password] ssh.config[:ssh_port] = Chef::Config[:knife][:ssh_port] || config[:ssh_port] ssh.config[:ssh_gateway] = Chef::Config[:knife][:ssh_gateway] || config[:ssh_gateway] ssh.config[:forward_agent] = Chef::Config[:knife][:forward_agent] || config[:forward_agent] ssh.config[:identity_file] = Chef::Config[:knife][:identity_file] || config[:identity_file] ssh.config[:manual] = true ssh.config[:host_key_verify] = Chef::Config[:knife][:host_key_verify] || config[:host_key_verify] ssh.config[:on_error] = :raise ssh end def knife_ssh_with_password_auth ssh = knife_ssh ssh.config[:identity_file] = nil ssh.config[:ssh_password] = ssh.get_password ssh end def ssh_command command = render_template(read_template) if config[:use_sudo] command = config[:use_sudo_password] ? "echo '#{config[:ssh_password]}' | sudo -S #{command}" : "sudo #{command}" end command end def warn_chef_config_secret_key unless Chef::Config[:encrypted_data_bag_secret].nil? ui.warn "* " * 40 ui.warn(<<-WARNING) Specifying the encrypted data bag secret key using an 'encrypted_data_bag_secret' entry in 'knife.rb' is deprecated. Please see CHEF-4011 for more details. You can supress this warning and still distribute the secret key to all bootstrapped machines by adding the following to your 'knife.rb' file: knife[:secret_file] = "/path/to/your/secret" If you would like to selectively distribute a secret key during bootstrap please use the '--secret' or '--secret-file' options of this command instead. #{ui.color('IMPORTANT:', :red, :bold)} In a future version of Chef, this behavior will be removed and any 'encrypted_data_bag_secret' entries in 'knife.rb' will be ignored completely. WARNING ui.warn "* " * 40 end end end end end chef-11.8.2/lib/chef/knife/role_create.rb0000644000004100000410000000257612254362222020132 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class RoleCreate < Knife deps do require 'chef/role' require 'chef/json_compat' end banner "knife role create ROLE (options)" option :description, :short => "-d DESC", :long => "--description DESC", :description => "The role description" def run @role_name = @name_args[0] if @role_name.nil? show_usage ui.fatal("You must specify a role name") exit 1 end role = Chef::Role.new role.name(@role_name) role.description(config[:description]) if config[:description] create_object(role) end end end end chef-11.8.2/lib/chef/knife/data_bag_show.rb0000644000004100000410000000501212254362222020414 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Seth Falcon () # Copyright:: Copyright (c) 2009-2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class DataBagShow < Knife deps do require 'chef/data_bag' require 'chef/encrypted_data_bag_item' end banner "knife data bag show BAG [ITEM] (options)" category "data bag" option :secret, :short => "-s SECRET", :long => "--secret ", :description => "The secret key to use to decrypt data bag item values", :proc => Proc.new { |s| Chef::Config[:knife][:secret] = s } option :secret_file, :long => "--secret-file SECRET_FILE", :description => "A file containing the secret key to use to decrypt data bag item values", :proc => Proc.new { |sf| Chef::Config[:knife][:secret_file] = sf } def read_secret if config[:secret] config[:secret] else Chef::EncryptedDataBagItem.load_secret(config[:secret_file]) end end def use_encryption if config[:secret] && config[:secret_file] stdout.puts "please specify only one of --secret, --secret-file" exit(1) end config[:secret] || config[:secret_file] end def run display = case @name_args.length when 2 if use_encryption raw = Chef::EncryptedDataBagItem.load(@name_args[0], @name_args[1], read_secret) format_for_display(raw.to_hash) else format_for_display(Chef::DataBagItem.load(@name_args[0], @name_args[1]).raw_data) end when 1 format_list_for_display(Chef::DataBag.load(@name_args[0])) else stdout.puts opt_parser exit(1) end output(display) end end end end chef-11.8.2/lib/chef/knife/cookbook_site_share.rb0000644000004100000410000001044112254362222021650 0ustar www-datawww-data# Author:: Nuo Yan () # Author:: Tim Hinderliter () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class CookbookSiteShare < Knife deps do require 'chef/cookbook_loader' require 'chef/cookbook_uploader' require 'chef/cookbook_site_streaming_uploader' end banner "knife cookbook site share COOKBOOK CATEGORY (options)" category "cookbook site" option :cookbook_path, :short => "-o PATH:PATH", :long => "--cookbook-path PATH:PATH", :description => "A colon-separated path to look for cookbooks in", :proc => lambda { |o| Chef::Config.cookbook_path = o.split(":") } def run if @name_args.length < 2 show_usage ui.fatal("You must specify the cookbook name and the category you want to share this cookbook to.") exit 1 end config[:cookbook_path] ||= Chef::Config[:cookbook_path] cookbook_name = @name_args[0] category = @name_args[1] cl = Chef::CookbookLoader.new(config[:cookbook_path]) if cl.cookbook_exists?(cookbook_name) cookbook = cl[cookbook_name] Chef::CookbookUploader.new(cookbook,config[:cookbook_path]).validate_cookbooks tmp_cookbook_dir = Chef::CookbookSiteStreamingUploader.create_build_dir(cookbook) begin Chef::Log.debug("Temp cookbook directory is #{tmp_cookbook_dir.inspect}") ui.info("Making tarball #{cookbook_name}.tgz") Chef::Mixin::Command.run_command(:command => "tar -czf #{cookbook_name}.tgz #{cookbook_name}", :cwd => tmp_cookbook_dir) rescue => e ui.error("Error making tarball #{cookbook_name}.tgz: #{e.message}. Set log level to debug (-l debug) for more information.") Chef::Log.debug("\n#{e.backtrace.join("\n")}") exit(1) end begin do_upload("#{tmp_cookbook_dir}/#{cookbook_name}.tgz", category, Chef::Config[:node_name], Chef::Config[:client_key]) ui.info("Upload complete!") Chef::Log.debug("Removing local staging directory at #{tmp_cookbook_dir}") FileUtils.rm_rf tmp_cookbook_dir rescue => e ui.error("Error uploading cookbook #{cookbook_name} to the Opscode Cookbook Site: #{e.message}. Set log level to debug (-l debug) for more information.") Chef::Log.debug("\n#{e.backtrace.join("\n")}") exit(1) end else ui.error("Could not find cookbook #{cookbook_name} in your cookbook path.") exit(1) end end def do_upload(cookbook_filename, cookbook_category, user_id, user_secret_filename) uri = "http://cookbooks.opscode.com/api/v1/cookbooks" category_string = { 'category'=>cookbook_category }.to_json http_resp = Chef::CookbookSiteStreamingUploader.post(uri, user_id, user_secret_filename, { :tarball => File.open(cookbook_filename), :cookbook => category_string }) res = Chef::JSONCompat.from_json(http_resp.body) if http_resp.code.to_i != 201 if res['error_messages'] if res['error_messages'][0] =~ /Version already exists/ ui.error "The same version of this cookbook already exists on the Opscode Cookbook Site." exit(1) else ui.error "#{res['error_messages'][0]}" exit(1) end else ui.error "Unknown error while sharing cookbook" ui.error "Server response: #{http_resp.body}" exit(1) end end res end end end end chef-11.8.2/lib/chef/knife/tag_create.rb0000644000004100000410000000263512254362222017740 0ustar www-datawww-data# # Author:: Ryan Davis () # Author:: Daniel DeLeo () # Author:: Nuo Yan () # Copyright:: Copyright (c) 2011 Ryan Davis and Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class TagCreate < Knife deps do require 'chef/node' end banner "knife tag create NODE TAG ..." def run name = @name_args[0] tags = @name_args[1..-1] if name.nil? || tags.nil? || tags.empty? show_usage ui.fatal("You must specify a node name and at least one tag.") exit 1 end node = Chef::Node.load name tags.each do |tag| (node.tags << tag).uniq! end node.save ui.info("Created tags #{tags.join(", ")} for node #{name}.") end end end end chef-11.8.2/lib/chef/knife/user_show.rb0000644000004100000410000000233112254362222017651 0ustar www-datawww-data# # Author:: Steven Danna () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class UserShow < Knife include Knife::Core::MultiAttributeReturnOption deps do require 'chef/user' require 'chef/json_compat' end banner "knife user show USER (options)" def run @user_name = @name_args[0] if @user_name.nil? show_usage ui.fatal("You must specify a user name") exit 1 end user = Chef::User.load(@user_name) output(format_for_display(user)) end end end end chef-11.8.2/lib/chef/knife/role_from_file.rb0000644000004100000410000000247612254362222020630 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class RoleFromFile < Knife deps do require 'chef/role' require 'chef/knife/core/object_loader' require 'chef/json_compat' end banner "knife role from file FILE [FILE..] (options)" def loader @loader ||= Knife::Core::ObjectLoader.new(Chef::Role, ui) end def run @name_args.each do |arg| updated = loader.load_from("roles", arg) updated.save output(format_for_display(updated)) if config[:print_after] ui.info("Updated Role #{updated.name}!") end end end end end chef-11.8.2/lib/chef/knife/node_bulk_delete.rb0000644000004100000410000000376012254362222021126 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class NodeBulkDelete < Knife deps do require 'chef/node' require 'chef/json_compat' end banner "knife node bulk delete REGEX (options)" def run if name_args.length < 1 ui.fatal("You must supply a regular expression to match the results against") exit 42 end nodes_to_delete = {} matcher = /#{name_args[0]}/ all_nodes.each do |name, node| next unless name =~ matcher nodes_to_delete[name] = node end if nodes_to_delete.empty? ui.msg "No nodes match the expression /#{name_args[0]}/" exit 0 end ui.msg("The following nodes will be deleted:") ui.msg("") ui.msg(ui.list(nodes_to_delete.keys.sort, :columns_down)) ui.msg("") ui.confirm("Are you sure you want to delete these nodes") nodes_to_delete.sort.each do |name, node| node.destroy ui.msg("Deleted node #{name}") end end def all_nodes node_uris_by_name = Chef::Node.list node_uris_by_name.keys.inject({}) do |nodes_by_name, name| nodes_by_name[name] = Chef::Node.new.tap {|n| n.name(name)} nodes_by_name end end end end end chef-11.8.2/lib/chef/knife/status.rb0000644000004100000410000000711412254362222017162 0ustar www-datawww-data# # Author:: Ian Meyer () # Copyright:: Copyright (c) 2010 Ian Meyer # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class Status < Knife deps do require 'highline' require 'chef/search/query' end banner "knife status QUERY (options)" option :run_list, :short => "-r", :long => "--run-list", :description => "Show the run list" option :sort_reverse, :short => "-s", :long => "--sort-reverse", :description => "Sort the status list by last run time descending" option :hide_healthy, :short => "-H", :long => "--hide-healthy", :description => "Hide nodes that have run chef in the last hour" def highline @h ||= HighLine.new end def run all_nodes = [] q = Chef::Search::Query.new query = @name_args[0] || "*:*" q.search(:node, query) do |node| all_nodes << node end all_nodes.sort { |n1, n2| if (config[:sort_reverse] || Chef::Config[:knife][:sort_status_reverse]) (n2["ohai_time"] or 0) <=> (n1["ohai_time"] or 0) else (n1["ohai_time"] or 0) <=> (n2["ohai_time"] or 0) end }.each do |node| if node.has_key?("ec2") fqdn = node['ec2']['public_hostname'] ipaddress = node['ec2']['public_ipv4'] else fqdn = node['fqdn'] ipaddress = node['ipaddress'] end hours, minutes, seconds = time_difference_in_hms(node["ohai_time"]) hours_text = "#{hours} hour#{hours == 1 ? ' ' : 's'}" minutes_text = "#{minutes} minute#{minutes == 1 ? ' ' : 's'}" run_list = "#{node.run_list}" if config[:run_list] if hours > 24 color = :red text = hours_text elsif hours >= 1 color = :yellow text = hours_text else color = :green text = minutes_text end line_parts = Array.new line_parts << @ui.color(text, color) + " ago" << node.name line_parts << fqdn if fqdn line_parts << ipaddress if ipaddress line_parts << run_list if run_list if node['platform'] platform = node['platform'] if node['platform_version'] platform << " #{node['platform_version']}" end line_parts << platform end highline.say(line_parts.join(', ') + '.') unless (config[:hide_healthy] && hours < 1) end end # :nodoc: # TODO: this is duplicated from StatusHelper in the Webui. dedup. def time_difference_in_hms(unix_time) now = Time.now.to_i difference = now - unix_time.to_i hours = (difference / 3600).to_i difference = difference % 3600 minutes = (difference / 60).to_i seconds = (difference % 60) return [hours, minutes, seconds] end end end end chef-11.8.2/lib/chef/knife/data_bag_list.rb0000644000004100000410000000214412254362222020412 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class DataBagList < Knife deps do require 'chef/data_bag' end banner "knife data bag list (options)" category "data bag" option :with_uri, :short => "-w", :long => "--with-uri", :description => "Show corresponding URIs" def run output(format_list_for_display(Chef::DataBag.list)) end end end end chef-11.8.2/lib/chef/knife/cookbook_site_download.rb0000644000004100000410000000607012254362222022360 0ustar www-datawww-data# Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class CookbookSiteDownload < Knife deps do require 'fileutils' end banner "knife cookbook site download COOKBOOK [VERSION] (options)" category "cookbook site" option :file, :short => "-f FILE", :long => "--file FILE", :description => "The filename to write to" option :force, :long => "--force", :description => "Force download deprecated version" def run if current_cookbook_deprecated? message = 'DEPRECATION: This cookbook has been deprecated. ' message << "It has been replaced by #{replacement_cookbook}." ui.warn message unless config[:force] ui.warn 'Use --force to force download deprecated cookbook.' return end end download_cookbook end def version @version = desired_cookbook_data['version'] end private def cookbooks_api_url 'http://cookbooks.opscode.com/api/v1/cookbooks' end def current_cookbook_data @current_cookbook_data ||= begin noauth_rest.get_rest "#{cookbooks_api_url}/#{@name_args[0]}" end end def current_cookbook_deprecated? current_cookbook_data['deprecated'] == true end def desired_cookbook_data @desired_cookbook_data ||= begin uri = if @name_args.length == 1 current_cookbook_data['latest_version'] else specific_cookbook_version_url end noauth_rest.get_rest uri end end def download_cookbook ui.info "Downloading #{@name_args[0]} from the cookbooks site at version #{version} to #{download_location}" noauth_rest.sign_on_redirect = false tf = noauth_rest.get_rest desired_cookbook_data["file"], true ::FileUtils.cp tf.path, download_location ui.info "Cookbook saved: #{download_location}" end def download_location config[:file] ||= File.join Dir.pwd, "#{@name_args[0]}-#{version}.tar.gz" config[:file] end def replacement_cookbook replacement = File.basename(current_cookbook_data['replacement']) end def specific_cookbook_version_url "#{cookbooks_api_url}/#{@name_args[0]}/versions/#{@name_args[1].gsub('.', '_')}" end end end end chef-11.8.2/lib/chef/knife/user_create.rb0000644000004100000410000000473312254362222020144 0ustar www-datawww-data# # Author:: Steven Danna () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class UserCreate < Knife deps do require 'chef/user' require 'chef/json_compat' end option :file, :short => "-f FILE", :long => "--file FILE", :description => "Write the private key to a file" option :admin, :short => "-a", :long => "--admin", :description => "Create the user as an admin", :boolean => true option :user_password, :short => "-p PASSWORD", :long => "--password PASSWORD", :description => "Password for newly created user", :default => "" option :user_key, :long => "--user-key FILENAME", :description => "Public key for newly created user. By default a key will be created for you." banner "knife user create USER (options)" def run @user_name = @name_args[0] if @user_name.nil? show_usage ui.fatal("You must specify a user name") exit 1 end if config[:user_password].length == 0 show_usage ui.fatal("You must specify a non-blank password") exit 1 end user = Chef::User.new user.name(@user_name) user.admin(config[:admin]) user.password config[:user_password] if config[:user_key] user.public_key File.read(File.expand_path(config[:user_key])) end output = edit_data(user) user = Chef::User.from_hash(output).create ui.info("Created #{user}") if user.private_key if config[:file] File.open(config[:file], "w") do |f| f.print(user.private_key) end else puts user.private_key end end end end end end chef-11.8.2/lib/chef/knife/client_show.rb0000644000004100000410000000236312254362222020156 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class ClientShow < Knife include Knife::Core::MultiAttributeReturnOption deps do require 'chef/api_client' require 'chef/json_compat' end banner "knife client show CLIENT (options)" def run @client_name = @name_args[0] if @client_name.nil? show_usage ui.fatal("You must specify a client name") exit 1 end client = Chef::ApiClient.load(@client_name) output(format_for_display(client)) end end end end chef-11.8.2/lib/chef/knife/cookbook_show.rb0000644000004100000410000000701112254362222020501 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class CookbookShow < Knife deps do require 'chef/json_compat' require 'uri' require 'chef/cookbook_version' end banner "knife cookbook show COOKBOOK [VERSION] [PART] [FILENAME] (options)" option :fqdn, :short => "-f FQDN", :long => "--fqdn FQDN", :description => "The FQDN of the host to see the file for" option :platform, :short => "-p PLATFORM", :long => "--platform PLATFORM", :description => "The platform to see the file for" option :platform_version, :short => "-V VERSION", :long => "--platform-version VERSION", :description => "The platform version to see the file for" option :with_uri, :short => "-w", :long => "--with-uri", :description => "Show corresponding URIs" def run case @name_args.length when 4 # We are showing a specific file node = Hash.new node[:fqdn] = config[:fqdn] if config.has_key?(:fqdn) node[:platform] = config[:platform] if config.has_key?(:platform) node[:platform_version] = config[:platform_version] if config.has_key?(:platform_version) class << node def attribute?(name) has_key?(name) end end cookbook_name, segment, filename = @name_args[0], @name_args[2], @name_args[3] cookbook_version = @name_args[1] == 'latest' ? '_latest' : @name_args[1] cookbook = rest.get_rest("cookbooks/#{cookbook_name}/#{cookbook_version}") manifest_entry = cookbook.preferred_manifest_record(node, segment, filename) temp_file = rest.get_rest(manifest_entry[:url], true) # the temp file is cleaned up elsewhere temp_file.open if temp_file.closed? pretty_print(temp_file.read) when 3 # We are showing a specific part of the cookbook cookbook_version = @name_args[1] == 'latest' ? '_latest' : @name_args[1] result = rest.get_rest("cookbooks/#{@name_args[0]}/#{cookbook_version}") output(result.manifest[@name_args[2]]) when 2 # We are showing the whole cookbook data cookbook_version = @name_args[1] == 'latest' ? '_latest' : @name_args[1] output(rest.get_rest("cookbooks/#{@name_args[0]}/#{cookbook_version}")) when 1 # We are showing the cookbook versions (all of them) cookbook_name = @name_args[0] env = config[:environment] api_endpoint = env ? "environments/#{env}/cookbooks/#{cookbook_name}" : "cookbooks/#{cookbook_name}" output(format_cookbook_list_for_display(rest.get_rest(api_endpoint))) when 0 show_usage ui.fatal("You must specify a cookbook name") exit 1 end end end end end chef-11.8.2/lib/chef/knife/exec.rb0000644000004100000410000000517012254362222016563 0ustar www-datawww-data#-- # Author:: Daniel DeLeo ( "-E CODE", :long => "--exec CODE", :description => "a string of Chef code to execute" option :script_path, :short => "-p PATH:PATH", :long => "--script-path PATH:PATH", :description => "A colon-separated path to look for scripts in", :proc => lambda { |o| o.split(":") } deps do require 'chef/shell/ext' end def run config[:script_path] ||= Array(Chef::Config[:script_path]) # Default script paths are chef-repo/.chef/scripts and ~/.chef/scripts config[:script_path] << File.join(Chef::Knife.chef_config_dir, 'scripts') if Chef::Knife.chef_config_dir config[:script_path] << File.join(ENV['HOME'], '.chef', 'scripts') if ENV['HOME'] scripts = Array(name_args) context = Object.new Shell::Extensions.extend_context_object(context) if config[:exec] context.instance_eval(config[:exec], "-E Argument", 0) elsif !scripts.empty? scripts.each do |script| file = find_script(script) context.instance_eval(IO.read(file), file, 0) end else script = STDIN.read context.instance_eval(script, "STDIN", 0) end end def find_script(x) # Try to find a script. First try expanding the path given. script = File.expand_path(x) return script if File.exists?(script) # Failing that, try searching the script path. If we can't find # anything, fail gracefully. Chef::Log.debug("Searching script_path: #{config[:script_path].inspect}") config[:script_path].each do |path| path = File.expand_path(path) test = File.join(path, x) Chef::Log.debug("Testing: #{test}") if File.exists?(test) script = test Chef::Log.debug("Found: #{test}") return script end end ui.error("\"#{x}\" not found in current directory or script_path, giving up.") exit(1) end end chef-11.8.2/lib/chef/knife/bootstrap/0000755000004100000410000000000012254362222017324 5ustar www-datawww-datachef-11.8.2/lib/chef/knife/bootstrap/ubuntu12.04-gems.erb0000644000004100000410000000221112254362222022652 0ustar www-datawww-databash -c ' <%= "export http_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%> if [ ! -f /usr/bin/chef-client ]; then aptitude update aptitude install -y ruby ruby1.8-dev build-essential wget libruby1.8 rubygems fi gem update --no-rdoc --no-ri gem install ohai --no-rdoc --no-ri --verbose gem install chef --no-rdoc --no-ri --verbose <%= bootstrap_version_string %> mkdir -p /etc/chef cat > /etc/chef/validation.pem <<'EOP' <%= validation_key %> EOP chmod 0600 /etc/chef/validation.pem <% if encrypted_data_bag_secret -%> cat > /etc/chef/encrypted_data_bag_secret <<'EOP' <%= encrypted_data_bag_secret %> EOP chmod 0600 /etc/chef/encrypted_data_bag_secret <% end -%> <%# Generate Ohai Hints -%> <% unless @chef_config[:knife][:hints].nil? || @chef_config[:knife][:hints].empty? -%> mkdir -p /etc/chef/ohai/hints <% @chef_config[:knife][:hints].each do |name, hash| -%> cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP' <%= hash.to_json %> EOP <% end -%> <% end -%> cat > /etc/chef/client.rb <<'EOP' <%= config_content %> EOP cat > /etc/chef/first-boot.json <<'EOP' <%= first_boot.to_json %> EOP <%= start_chef %>' chef-11.8.2/lib/chef/knife/bootstrap/chef-full.erb0000644000004100000410000000314612254362222021667 0ustar www-datawww-databash -c ' <%= "export https_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%> distro=`uname -s` if test "x$distro" = "xSunOS"; then if test -d "/usr/sfw/bin"; then PATH=/usr/sfw/bin:$PATH export PATH fi fi exists() { if command -v $1 &>/dev/null then return 0 else return 1 fi } install_sh="https://www.opscode.com/chef/install.sh" version_string="-v <%= chef_version %>" if ! exists /usr/bin/chef-client; then if exists wget; then bash <(wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %> ${install_sh} -O -) ${version_string} elif exists curl; then bash <(curl -L <%= "--proxy \"#{knife_config[:bootstrap_proxy]}\" " if knife_config[:bootstrap_proxy] %> ${install_sh}) ${version_string} else echo "Neither wget nor curl found. Please install one and try again." >&2 exit 1 fi fi mkdir -p /etc/chef cat > /etc/chef/validation.pem <<'EOP' <%= validation_key %> EOP chmod 0600 /etc/chef/validation.pem <% if encrypted_data_bag_secret -%> cat > /etc/chef/encrypted_data_bag_secret <<'EOP' <%= encrypted_data_bag_secret %> EOP chmod 0600 /etc/chef/encrypted_data_bag_secret <% end -%> <%# Generate Ohai Hints -%> <% unless @chef_config[:knife][:hints].nil? || @chef_config[:knife][:hints].empty? -%> mkdir -p /etc/chef/ohai/hints <% @chef_config[:knife][:hints].each do |name, hash| -%> cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP' <%= hash.to_json %> EOP <% end -%> <% end -%> cat > /etc/chef/client.rb <<'EOP' <%= config_content %> EOP cat > /etc/chef/first-boot.json <<'EOP' <%= first_boot.to_json %> EOP <%= start_chef %>' chef-11.8.2/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb0000644000004100000410000000253612254362222022662 0ustar www-datawww-databash -c ' <%= "export http_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%> if [ ! -f /usr/bin/chef-client ]; then apt-get update apt-get install -y ruby ruby1.8-dev build-essential wget libruby-extras libruby1.8-extras wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %>http://production.cf.rubygems.org/rubygems/rubygems-1.6.2.tgz -O - | tar zxf - (cd rubygems-1.6.2 && ruby setup.rb --no-format-executable) fi gem update --no-rdoc --no-ri gem install ohai --no-rdoc --no-ri --verbose gem install chef --no-rdoc --no-ri --verbose <%= bootstrap_version_string %> mkdir -p /etc/chef cat > /etc/chef/validation.pem <<'EOP' <%= validation_key %> EOP chmod 0600 /etc/chef/validation.pem <% if encrypted_data_bag_secret -%> cat > /etc/chef/encrypted_data_bag_secret <<'EOP' <%= encrypted_data_bag_secret %> EOP chmod 0600 /etc/chef/encrypted_data_bag_secret <% end -%> <%# Generate Ohai Hints -%> <% unless @chef_config[:knife][:hints].nil? || @chef_config[:knife][:hints].empty? -%> mkdir -p /etc/chef/ohai/hints <% @chef_config[:knife][:hints].each do |name, hash| -%> cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP' <%= hash.to_json %> EOP <% end -%> <% end -%> cat > /etc/chef/client.rb <<'EOP' <%= config_content %> EOP cat > /etc/chef/first-boot.json <<'EOP' <%= first_boot.to_json %> EOP <%= start_chef %>' chef-11.8.2/lib/chef/knife/bootstrap/fedora13-gems.erb0000644000004100000410000000211212254362222022347 0ustar www-datawww-databash -c ' <%= "export http_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%> yum install -y ruby ruby-devel gcc gcc-c++ automake autoconf rubygems make gem update --system gem update gem install ohai --no-rdoc --no-ri --verbose gem install chef --no-rdoc --no-ri --verbose <%= bootstrap_version_string %> mkdir -p /etc/chef cat > /etc/chef/validation.pem <<'EOP' <%= validation_key %> EOP chmod 0600 /etc/chef/validation.pem <% if encrypted_data_bag_secret -%> cat > /etc/chef/encrypted_data_bag_secret <<'EOP' <%= encrypted_data_bag_secret %> EOP chmod 0600 /etc/chef/encrypted_data_bag_secret <% end -%> <%# Generate Ohai Hints -%> <% unless @chef_config[:knife][:hints].nil? || @chef_config[:knife][:hints].empty? -%> mkdir -p /etc/chef/ohai/hints <% @chef_config[:knife][:hints].each do |name, hash| -%> cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP' <%= hash.to_json %> EOP <% end -%> <% end -%> cat > /etc/chef/client.rb <<'EOP' <%= config_content %> EOP cat > /etc/chef/first-boot.json <<'EOP' <%= first_boot.to_json %> EOP <%= start_chef %>' chef-11.8.2/lib/chef/knife/bootstrap/centos5-gems.erb0000644000004100000410000000333212254362222022330 0ustar www-datawww-databash -c ' <%= "export http_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%> if [ ! -f /usr/bin/chef-client ]; then tmp_dir=$(mktemp -d) || exit 1 pushd "$tmp_dir" yum install -y wget wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %>http://dl.fedoraproject.org/pub/epel/5/i386/epel-release-5-4.noarch.rpm rpm -Uvh epel-release-5-4.noarch.rpm wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %>http://rpm.aegisco.com/aegisco/rhel/aegisco-rhel.rpm rpm -Uvh aegisco-rhel.rpm yum install -y ruby ruby-devel gcc gcc-c++ automake autoconf make wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %>http://production.cf.rubygems.org/rubygems/rubygems-1.6.2.tgz -O - | tar zxf - (cd rubygems-1.6.2 && ruby setup.rb --no-format-executable) popd rm -r "$tmp_dir" fi gem update --system gem update gem install ohai --no-rdoc --no-ri --verbose gem install chef --no-rdoc --no-ri --verbose <%= bootstrap_version_string %> mkdir -p /etc/chef cat > /etc/chef/validation.pem <<'EOP' <%= validation_key %> EOP chmod 0600 /etc/chef/validation.pem <% if encrypted_data_bag_secret -%> cat > /etc/chef/encrypted_data_bag_secret <<'EOP' <%= encrypted_data_bag_secret %> EOP chmod 0600 /etc/chef/encrypted_data_bag_secret <% end -%> <%# Generate Ohai Hints -%> <% unless @chef_config[:knife][:hints].nil? || @chef_config[:knife][:hints].empty? -%> mkdir -p /etc/chef/ohai/hints <% @chef_config[:knife][:hints].each do |name, hash| -%> cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP' <%= hash.to_json %> EOP <% end -%> <% end -%> cat > /etc/chef/client.rb <<'EOP' <%= config_content %> EOP cat > /etc/chef/first-boot.json <<'EOP' <%= first_boot.to_json %> EOP <%= start_chef %>' chef-11.8.2/lib/chef/knife/bootstrap/archlinux-gems.erb0000644000004100000410000000345212254362222022750 0ustar www-datawww-databash -c ' <%= "export http_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%> if [ ! -f /usr/bin/chef-client ]; then pacman -Syy pacman -S --noconfirm ruby ntp base-devel ntpdate -u pool.ntp.org gem install ohai --no-rdoc --no-ri --verbose gem install chef --no-rdoc --no-ri --verbose <%= bootstrap_version_string %> fi mkdir -p /etc/chef cat > /etc/chef/validation.pem <<'EOP' <%= validation_key %> EOP chmod 0600 /etc/chef/validation.pem <% if encrypted_data_bag_secret -%> cat > /etc/chef/encrypted_data_bag_secret <<'EOP' <%= encrypted_data_bag_secret %> EOP chmod 0600 /etc/chef/encrypted_data_bag_secret <% end -%> <%# Generate Ohai Hints -%> <% unless @chef_config[:knife][:hints].nil? || @chef_config[:knife][:hints].empty? -%> mkdir -p /etc/chef/ohai/hints <% @chef_config[:knife][:hints].each do |name, hash| -%> cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP' <%= hash.to_json %> EOP <% end -%> <% end -%> cat > /etc/chef/client.rb <<'EOP' log_level :info log_location STDOUT chef_server_url "<%= @chef_config[:chef_server_url] %>" validation_client_name "<%= @chef_config[:validation_client_name] %>" <% if @config[:chef_node_name] -%> node_name "<%= @config[:chef_node_name] %>" <% else -%> # Using default node name (fqdn) <% end -%> # ArchLinux follows the Filesystem Hierarchy Standard file_cache_path "/var/cache/chef" file_backup_path "/var/lib/chef/backup" pid_file "/var/run/chef/client.pid" cache_options({ :path => "/var/cache/chef/checksums", :skip_expires => true}) <% if knife_config[:bootstrap_proxy] %> http_proxy "<%= knife_config[:bootstrap_proxy] %>" https_proxy "<%= knife_config[:bootstrap_proxy] %>" <% end -%> EOP cat > /etc/chef/first-boot.json <<'EOP' <%= first_boot.to_json %> EOP <%= start_chef %>' chef-11.8.2/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb0000644000004100000410000000375312254362222022515 0ustar www-datawww-databash -c ' <%= "export http_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%> if [ ! -f /usr/bin/chef-client ]; then apt-get install -y wget echo "chef chef/chef_server_url string <%= @chef_config[:chef_server_url] %>" | debconf-set-selections [ -f /etc/apt/sources.list.d/opscode.list ] || echo "deb http://apt.opscode.com <%= chef_version.to_f == 0.10 ? "lucid-0.10" : "lucid" %> main" > /etc/apt/sources.list.d/opscode.list wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %>-O- http://apt.opscode.com/packages@opscode.com.gpg.key | apt-key add - fi apt-get update apt-get install -y chef cat > /etc/chef/validation.pem <<'EOP' <%= validation_key %> EOP chmod 0600 /etc/chef/validation.pem <% if encrypted_data_bag_secret -%> cat > /etc/chef/encrypted_data_bag_secret <<'EOP' <%= encrypted_data_bag_secret %> EOP chmod 0600 /etc/chef/encrypted_data_bag_secret <% end -%> <%# Generate Ohai Hints -%> <% unless @chef_config[:knife][:hints].nil? || @chef_config[:knife][:hints].empty? -%> mkdir -p /etc/chef/ohai/hints <% @chef_config[:knife][:hints].each do |name, hash| -%> cat > /etc/chef/ohai/hints/<%= name %>.json <<'EOP' <%= hash.to_json %> EOP <% end -%> <% end -%> <% unless @chef_config[:validation_client_name] == "chef-validator" -%> [ `grep -qx "validation_client_name \"<%= @chef_config[:validation_client_name] %>\"" /etc/chef/client.rb` ] || echo "validation_client_name \"<%= @chef_config[:validation_client_name] %>\"" >> /etc/chef/client.rb <% end -%> <% if @config[:chef_node_name] %> [ `grep -qx "node_name \"<%= @config[:chef_node_name] %>\"" /etc/chef/client.rb` ] || echo "node_name \"<%= @config[:chef_node_name] %>\"" >> /etc/chef/client.rb <% end -%> <% if knife_config[:bootstrap_proxy] %> echo 'http_proxy "knife_config[:bootstrap_proxy]"' >> /etc/chef/client.rb echo 'https_proxy "knife_config[:bootstrap_proxy]"' >> /etc/chef/client.rb <% end -%> cat > /etc/chef/first-boot.json <<'EOP' <%= first_boot.to_json %> EOP <%= start_chef %>' chef-11.8.2/lib/chef/knife/configure.rb0000644000004100000410000001517612254362222017627 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class Configure < Knife attr_reader :chef_server, :new_client_name, :admin_client_name, :admin_client_key attr_reader :chef_repo, :new_client_key, :validation_client_name, :validation_key deps do require 'ohai' Chef::Knife::ClientCreate.load_deps Chef::Knife::UserCreate.load_deps end banner "knife configure (options)" option :repository, :short => "-r REPO", :long => "--repository REPO", :description => "The path to your chef-repo" option :initial, :short => "-i", :long => "--initial", :boolean => true, :description => "Create an initial API User" option :admin_client_name, :long => "--admin-client-name NAME", :description => "The existing admin clientname (usually admin)" option :admin_client_key, :long => "--admin-client-key PATH", :description => "The path to the admin client's private key (usually a file named admin.pem)" option :validation_client_name, :long => "--validation-client-name NAME", :description => "The validation clientname (usually chef-validator)" option :validation_key, :long => "--validation-key PATH", :description => "The location of the validation key (usually a file named validation.pem)" def configure_chef # We are just faking out the system so that you can do this without a key specified Chef::Config[:node_name] = 'woot' super Chef::Config[:node_name] = nil end def run ask_user_for_config_path FileUtils.mkdir_p(chef_config_path) ask_user_for_config ::File.open(config[:config_file], "w") do |f| f.puts <<-EOH log_level :info log_location STDOUT node_name '#{new_client_name}' client_key '#{new_client_key}' validation_client_name '#{validation_client_name}' validation_key '#{validation_key}' chef_server_url '#{chef_server}' syntax_check_cache_path '#{File.join(chef_config_path, "syntax_check_cache")}' EOH unless chef_repo.empty? f.puts "cookbook_path [ '#{chef_repo}/cookbooks' ]" end end if config[:initial] ui.msg("Creating initial API user...") Chef::Config[:chef_server_url] = chef_server Chef::Config[:node_name] = admin_client_name Chef::Config[:client_key] = admin_client_key user_create = Chef::Knife::UserCreate.new user_create.name_args = [ new_client_name ] user_create.config[:user_password] = config[:user_password] || ui.ask("Please enter a password for the new user: ") {|q| q.echo = false} user_create.config[:admin] = true user_create.config[:file] = new_client_key user_create.config[:yes] = true user_create.config[:disable_editing] = true user_create.run else ui.msg("*****") ui.msg("") ui.msg("You must place your client key in:") ui.msg(" #{new_client_key}") ui.msg("Before running commands with Knife!") ui.msg("") ui.msg("*****") ui.msg("") ui.msg("You must place your validation key in:") ui.msg(" #{validation_key}") ui.msg("Before generating instance data with Knife!") ui.msg("") ui.msg("*****") end ui.msg("Configuration file written to #{config[:config_file]}") end def ask_user_for_config_path config[:config_file] ||= ask_question("Where should I put the config file? ", :default => "#{Chef::Config[:user_home]}/.chef/knife.rb") # have to use expand path to expand the tilde character to the user's home config[:config_file] = File.expand_path(config[:config_file]) if File.exists?(config[:config_file]) confirm("Overwrite #{config[:config_file]}") end end def ask_user_for_config server_name = guess_servername @chef_server = config[:chef_server_url] || ask_question("Please enter the chef server URL: ", :default => "https://#{server_name}:443") if config[:initial] @new_client_name = config[:node_name] || ask_question("Please enter a name for the new user: ", :default => Etc.getlogin) @admin_client_name = config[:admin_client_name] || ask_question("Please enter the existing admin name: ", :default => 'admin') @admin_client_key = config[:admin_client_key] || ask_question("Please enter the location of the existing admin's private key: ", :default => '/etc/chef-server/admin.pem') @admin_client_key = File.expand_path(@admin_client_key) else @new_client_name = config[:node_name] || ask_question("Please enter an existing username or clientname for the API: ", :default => Etc.getlogin) end @validation_client_name = config[:validation_client_name] || ask_question("Please enter the validation clientname: ", :default => 'chef-validator') @validation_key = config[:validation_key] || ask_question("Please enter the location of the validation key: ", :default => '/etc/chef-server/chef-validator.pem') @validation_key = File.expand_path(@validation_key) @chef_repo = config[:repository] || ask_question("Please enter the path to a chef repository (or leave blank): ") @new_client_key = config[:client_key] || File.join(chef_config_path, "#{@new_client_name}.pem") @new_client_key = File.expand_path(@new_client_key) end def guess_servername o = Ohai::System.new o.require_plugin 'os' o.require_plugin 'hostname' o[:fqdn] || 'localhost' end def config_file config[:config_file] end def chef_config_path File.dirname(config_file) end end end end chef-11.8.2/lib/chef/knife/node_show.rb0000644000004100000410000000337112254362222017625 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' require 'chef/knife/core/node_presenter' class Chef class Knife class NodeShow < Knife include Knife::Core::NodeFormattingOptions include Knife::Core::MultiAttributeReturnOption deps do require 'chef/node' require 'chef/json_compat' end banner "knife node show NODE (options)" option :run_list, :short => "-r", :long => "--run-list", :description => "Show only the run list" option :environment, :short => "-E", :long => "--environment", :description => "Show only the Chef environment" def run ui.use_presenter Knife::Core::NodePresenter @node_name = @name_args[0] if @node_name.nil? show_usage ui.fatal("You must specify a node name") exit 1 end node = Chef::Node.load(@node_name) output(format_for_display(node)) self.class.attrs_to_show = [] end def self.attrs_to_show=(attrs) @attrs_to_show = attrs end end end end chef-11.8.2/lib/chef/knife/cookbook_create.rb0000644000004100000410000003475512254362222021003 0ustar www-datawww-data# # Author:: Nuo Yan () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class CookbookCreate < Knife deps do require 'chef/json_compat' require 'uri' require 'fileutils' end banner "knife cookbook create COOKBOOK (options)" option :cookbook_path, :short => "-o PATH", :long => "--cookbook-path PATH", :description => "The directory where the cookbook will be created" option :readme_format, :short => "-r FORMAT", :long => "--readme-format FORMAT", :description => "Format of the README file, supported formats are 'md' (markdown) and 'rdoc' (rdoc)" option :cookbook_license, :short => "-I LICENSE", :long => "--license LICENSE", :description => "License for cookbook, apachev2, gplv2, gplv3, mit or none" option :cookbook_copyright, :short => "-C COPYRIGHT", :long => "--copyright COPYRIGHT", :description => "Name of Copyright holder" option :cookbook_email, :short => "-m EMAIL", :long => "--email EMAIL", :description => "Email address of cookbook maintainer" def run self.config = Chef::Config.merge!(config) if @name_args.length < 1 show_usage ui.fatal("You must specify a cookbook name") exit 1 end if default_cookbook_path_empty? && parameter_empty?(config[:cookbook_path]) raise ArgumentError, "Default cookbook_path is not specified in the knife.rb config file, and a value to -o is not provided. Nowhere to write the new cookbook to." end cookbook_path = File.expand_path(Array(config[:cookbook_path]).first) cookbook_name = @name_args.first copyright = config[:cookbook_copyright] || "YOUR_COMPANY_NAME" email = config[:cookbook_email] || "YOUR_EMAIL" license = ((config[:cookbook_license] != "false") && config[:cookbook_license]) || "none" readme_format = ((config[:readme_format] != "false") && config[:readme_format]) || "md" create_cookbook(cookbook_path, cookbook_name, copyright, license) create_readme(cookbook_path, cookbook_name, readme_format) create_changelog(cookbook_path, cookbook_name) create_metadata(cookbook_path, cookbook_name, copyright, email, license, readme_format) end def create_cookbook(dir, cookbook_name, copyright, license) msg("** Creating cookbook #{cookbook_name}") FileUtils.mkdir_p "#{File.join(dir, cookbook_name, "attributes")}" FileUtils.mkdir_p "#{File.join(dir, cookbook_name, "recipes")}" FileUtils.mkdir_p "#{File.join(dir, cookbook_name, "definitions")}" FileUtils.mkdir_p "#{File.join(dir, cookbook_name, "libraries")}" FileUtils.mkdir_p "#{File.join(dir, cookbook_name, "resources")}" FileUtils.mkdir_p "#{File.join(dir, cookbook_name, "providers")}" FileUtils.mkdir_p "#{File.join(dir, cookbook_name, "files", "default")}" FileUtils.mkdir_p "#{File.join(dir, cookbook_name, "templates", "default")}" unless File.exists?(File.join(dir, cookbook_name, "recipes", "default.rb")) open(File.join(dir, cookbook_name, "recipes", "default.rb"), "w") do |file| file.puts <<-EOH # # Cookbook Name:: #{cookbook_name} # Recipe:: default # # Copyright #{Time.now.year}, #{copyright} # EOH case license when "apachev2" file.puts <<-EOH # 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. # EOH when "gplv2" file.puts <<-EOH # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # EOH when "gplv3" file.puts <<-EOH # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # EOH when "mit" file.puts <<-EOH # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # EOH when "none" file.puts <<-EOH # All rights reserved - Do Not Redistribute # EOH end end end end def create_changelog(dir, cookbook_name) msg("** Creating CHANGELOG for cookbook: #{cookbook_name}") unless File.exists?(File.join(dir,cookbook_name,'CHANGELOG.md')) open(File.join(dir, cookbook_name, 'CHANGELOG.md'),'w') do |file| file.puts <<-EOH #{cookbook_name} CHANGELOG #{'='*"#{cookbook_name} CHANGELOG".length} This file is used to list changes made in each version of the #{cookbook_name} cookbook. 0.1.0 ----- - [your_name] - Initial release of #{cookbook_name} - - - Check the [Markdown Syntax Guide](http://daringfireball.net/projects/markdown/syntax) for help with Markdown. The [Github Flavored Markdown page](http://github.github.com/github-flavored-markdown/) describes the differences between markdown on github and standard markdown. EOH end end end def create_readme(dir, cookbook_name, readme_format) msg("** Creating README for cookbook: #{cookbook_name}") unless File.exists?(File.join(dir, cookbook_name, "README.#{readme_format}")) open(File.join(dir, cookbook_name, "README.#{readme_format}"), "w") do |file| case readme_format when "rdoc" file.puts <<-EOH = #{cookbook_name} Cookbook TODO: Enter the cookbook description here. e.g. This cookbook makes your favorite breakfast sandwich. == Requirements TODO: List your cookbook requirements. Be sure to include any requirements this cookbook has on platforms, libraries, other cookbooks, packages, operating systems, etc. e.g. ==== packages - +toaster+ - #{cookbook_name} needs toaster to brown your bagel. == Attributes TODO: List your cookbook attributes here. e.g. ==== #{cookbook_name}::default
Key Type Description Default
['#{cookbook_name}']['bacon'] Boolean whether to include bacon true
== Usage ==== #{cookbook_name}::default TODO: Write usage instructions for each cookbook. e.g. Just include +#{cookbook_name}+ in your node's +run_list+: { "name":"my_node", "run_list": [ "recipe[#{cookbook_name}]" ] } == Contributing TODO: (optional) If this is a public cookbook, detail the process for contributing. If this is a private cookbook, remove this section. e.g. 1. Fork the repository on Github 2. Create a named feature branch (like `add_component_x`) 3. Write your change 4. Write tests for your change (if applicable) 5. Run the tests, ensuring they all pass 6. Submit a Pull Request using Github == License and Authors Authors: TODO: List authors EOH when "md","mkd","txt" file.puts <<-EOH #{cookbook_name} Cookbook #{'='*"#{cookbook_name} Cookbook".length} TODO: Enter the cookbook description here. e.g. This cookbook makes your favorite breakfast sandwich. Requirements ------------ TODO: List your cookbook requirements. Be sure to include any requirements this cookbook has on platforms, libraries, other cookbooks, packages, operating systems, etc. e.g. #### packages - `toaster` - #{cookbook_name} needs toaster to brown your bagel. Attributes ---------- TODO: List you cookbook attributes here. e.g. #### #{cookbook_name}::default
Key Type Description Default
['#{cookbook_name}']['bacon'] Boolean whether to include bacon true
Usage ----- #### #{cookbook_name}::default TODO: Write usage instructions for each cookbook. e.g. Just include `#{cookbook_name}` in your node's `run_list`: ```json { "name":"my_node", "run_list": [ "recipe[#{cookbook_name}]" ] } ``` Contributing ------------ TODO: (optional) If this is a public cookbook, detail the process for contributing. If this is a private cookbook, remove this section. e.g. 1. Fork the repository on Github 2. Create a named feature branch (like `add_component_x`) 3. Write your change 4. Write tests for your change (if applicable) 5. Run the tests, ensuring they all pass 6. Submit a Pull Request using Github License and Authors ------------------- Authors: TODO: List authors EOH else file.puts <<-EOH #{cookbook_name} Cookbook #{'='*"#{cookbook_name} Cookbook".length} TODO: Enter the cookbook description here. e.g. This cookbook makes your favorite breakfast sandwich. Requirements TODO: List your cookbook requirements. Be sure to include any requirements this cookbook has on platforms, libraries, other cookbooks, packages, operating systems, etc. e.g. toaster #{cookbook_name} needs toaster to brown your bagel. Attributes TODO: List you cookbook attributes here. #{cookbook_name} Key Type Description Default ['#{cookbook_name}']['bacon'] Boolean whether to include bacon true Usage #{cookbook_name} TODO: Write usage instructions for each cookbook. e.g. Just include `#{cookbook_name}` in your node's `run_list`: [code] { "name":"my_node", "run_list": [ "recipe[#{cookbook_name}]" ] } [/code] Contributing TODO: (optional) If this is a public cookbook, detail the process for contributing. If this is a private cookbook, remove this section. e.g. 1. Fork the repository on Github 2. Create a named feature branch (like `add_component_x`) 3. Write your change 4. Write tests for your change (if applicable) 5. Run the tests, ensuring they all pass 6. Submit a Pull Request using Github License and Authors Authors: TODO: List authors EOH end end end end def create_metadata(dir, cookbook_name, copyright, email, license, readme_format) msg("** Creating metadata for cookbook: #{cookbook_name}") license_name = case license when "apachev2" "Apache 2.0" when "gplv2" "GNU Public License 2.0" when "gplv3" "GNU Public License 3.0" when "mit" "MIT" when "none" "All rights reserved" end unless File.exists?(File.join(dir, cookbook_name, "metadata.rb")) open(File.join(dir, cookbook_name, "metadata.rb"), "w") do |file| if File.exists?(File.join(dir, cookbook_name, "README.#{readme_format}")) long_description = "long_description IO.read(File.join(File.dirname(__FILE__), 'README.#{readme_format}'))" end file.puts <<-EOH name '#{cookbook_name}' maintainer '#{copyright}' maintainer_email '#{email}' license '#{license_name}' description 'Installs/Configures #{cookbook_name}' #{long_description} version '0.1.0' EOH end end end private def default_cookbook_path_empty? Chef::Config[:cookbook_path].nil? || Chef::Config[:cookbook_path].empty? end def parameter_empty?(parameter) parameter.nil? || parameter.empty? end end end end chef-11.8.2/lib/chef/knife/environment_list.rb0000644000004100000410000000217612254362222021241 0ustar www-datawww-data# # Author:: Stephen Delano () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class EnvironmentList < Knife deps do require 'chef/environment' require 'chef/json_compat' end banner "knife environment list (options)" option :with_uri, :short => "-w", :long => "--with-uri", :description => "Show corresponding URIs" def run output(format_list_for_display(Chef::Environment.list)) end end end end chef-11.8.2/lib/chef/knife/node_create.rb0000644000004100000410000000225112254362222020104 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class NodeCreate < Knife deps do require 'chef/node' require 'chef/json_compat' end banner "knife node create NODE (options)" def run @node_name = @name_args[0] if @node_name.nil? show_usage ui.fatal("You must specify a node name") exit 1 end node = Chef::Node.new node.name(@node_name) create_object(node) end end end end chef-11.8.2/lib/chef/knife/cookbook_site_install.rb0000644000004100000410000001231512254362222022216 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' require 'shellwords' class Chef class Knife class CookbookSiteInstall < Knife deps do require 'chef/mixin/shell_out' require 'chef/knife/core/cookbook_scm_repo' require 'chef/cookbook/metadata' end banner "knife cookbook site install COOKBOOK [VERSION] (options)" category "cookbook site" option :no_deps, :short => "-D", :long => "--skip-dependencies", :boolean => true, :default => false, :description => "Skips automatic dependency installation." option :cookbook_path, :short => "-o PATH:PATH", :long => "--cookbook-path PATH:PATH", :description => "A colon-separated path to look for cookbooks in", :proc => lambda { |o| o.split(":") } option :default_branch, :short => "-B BRANCH", :long => "--branch BRANCH", :description => "Default branch to work with", :default => "master" option :use_current_branch, :short => "-b", :long => "--use-current-branch", :description => "Use the current branch", :boolean => true, :default => false attr_reader :cookbook_name attr_reader :vendor_path def run extend Chef::Mixin::ShellOut if config[:cookbook_path] Chef::Config[:cookbook_path] = config[:cookbook_path] else config[:cookbook_path] = Chef::Config[:cookbook_path] end @cookbook_name = parse_name_args! # Check to ensure we have a valid source of cookbooks before continuing # @install_path = File.expand_path(Array(config[:cookbook_path]).first) ui.info "Installing #@cookbook_name to #{@install_path}" @repo = CookbookSCMRepo.new(@install_path, ui, config) #cookbook_path = File.join(vendor_path, name_args[0]) upstream_file = File.join(@install_path, "#{@cookbook_name}.tar.gz") @repo.sanity_check unless config[:use_current_branch] @repo.reset_to_default_state @repo.prepare_to_import(@cookbook_name) end downloader = download_cookbook_to(upstream_file) clear_existing_files(File.join(@install_path, @cookbook_name)) extract_cookbook(upstream_file, downloader.version) # TODO: it'd be better to store these outside the cookbook repo and # keep them around, e.g., in ~/Library/Caches on OS X. ui.info("removing downloaded tarball") File.unlink(upstream_file) if @repo.finalize_updates_to(@cookbook_name, downloader.version) unless config[:use_current_branch] @repo.reset_to_default_state end @repo.merge_updates_from(@cookbook_name, downloader.version) else unless config[:use_current_branch] @repo.reset_to_default_state end end unless config[:no_deps] md = Chef::Cookbook::Metadata.new md.from_file(File.join(@install_path, @cookbook_name, "metadata.rb")) md.dependencies.each do |cookbook, version_list| # Doesn't do versions.. yet nv = self.class.new nv.config = config nv.name_args = [ cookbook ] nv.run end end end def parse_name_args! if name_args.empty? ui.error("Please specify a cookbook to download and install.") exit 1 elsif name_args.size >= 2 unless name_args.last.match(/^(\d+)(\.\d+){1,2}$/) and name_args.size == 2 ui.error("Installing multiple cookbooks at once is not supported.") exit 1 end end name_args.first end def download_cookbook_to(download_path) downloader = Chef::Knife::CookbookSiteDownload.new downloader.config[:file] = download_path downloader.name_args = name_args downloader.run downloader end def extract_cookbook(upstream_file, version) ui.info("Uncompressing #{@cookbook_name} version #{version}.") shell_out!("tar zxvf #{convert_path upstream_file}", :cwd => @install_path) end def clear_existing_files(cookbook_path) ui.info("Removing pre-existing version.") FileUtils.rmtree(cookbook_path) if File.directory?(cookbook_path) end def convert_path(upstream_file) if ENV['MSYSTEM'] == 'MINGW32' return upstream_file.sub(/^([[:alpha:]]):/, '/\1') else return Shellwords.escape upstream_file end end end end end chef-11.8.2/lib/chef/knife/data_bag_from_file.rb0000644000004100000410000001004012254362222021373 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Seth Falcon () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class DataBagFromFile < Knife deps do require 'chef/data_bag' require 'chef/data_bag_item' require 'chef/knife/core/object_loader' require 'chef/json_compat' require 'chef/encrypted_data_bag_item' end banner "knife data bag from file BAG FILE|FOLDER [FILE|FOLDER..] (options)" category "data bag" option :secret, :short => "-s SECRET", :long => "--secret ", :description => "The secret key to use to encrypt data bag item values", :proc => Proc.new { |s| Chef::Config[:knife][:secret] = s } option :secret_file, :long => "--secret-file SECRET_FILE", :description => "A file containing the secret key to use to encrypt data bag item values", :proc => Proc.new { |sf| Chef::Config[:knife][:secret_file] = sf } option :all, :short => "-a", :long => "--all", :description => "Upload all data bags or all items for specified data bags" def read_secret if config[:secret] config[:secret] else Chef::EncryptedDataBagItem.load_secret(config[:secret_file]) end end def use_encryption if config[:secret] && config[:secret_file] ui.fatal("please specify only one of --secret, --secret-file") exit(1) end config[:secret] || config[:secret_file] end def loader @loader ||= Knife::Core::ObjectLoader.new(DataBagItem, ui) end def run if config[:all] == true load_all_data_bags(@name_args) else if @name_args.size < 2 ui.msg(opt_parser) exit(1) end @data_bag = @name_args.shift load_data_bag_items(@data_bag, @name_args) end end private def data_bags_path @data_bag_path ||= "data_bags" end def find_all_data_bags loader.find_all_object_dirs("./#{data_bags_path}") end def find_all_data_bag_items(data_bag) loader.find_all_objects("./#{data_bags_path}/#{data_bag}") end def load_all_data_bags(args) data_bags = args.empty? ? find_all_data_bags : [args.shift] data_bags.each do |data_bag| load_data_bag_items(data_bag) end end def load_data_bag_items(data_bag, items = nil) items ||= find_all_data_bag_items(data_bag) item_paths = normalize_item_paths(items) item_paths.each do |item_path| item = loader.load_from("#{data_bags_path}", data_bag, item_path) item = if use_encryption secret = read_secret Chef::EncryptedDataBagItem.encrypt_data_bag_item(item, secret) else item end dbag = Chef::DataBagItem.new dbag.data_bag(data_bag) dbag.raw_data = item dbag.save ui.info("Updated data_bag_item[#{dbag.data_bag}::#{dbag.id}]") end end def normalize_item_paths(args) paths = Array.new args.each do |path| if File.directory?(path) paths.concat(Dir.glob(File.join(path, "*.json"))) else paths << path end end paths end end end end chef-11.8.2/lib/chef/knife/environment_edit.rb0000644000004100000410000000224212254362222021205 0ustar www-datawww-data# # Author:: Stephen Delano () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class EnvironmentEdit < Knife deps do require 'chef/environment' require 'chef/json_compat' end banner "knife environment edit ENVIRONMENT (options)" def run env_name = @name_args[0] if env_name.nil? show_usage ui.fatal("You must specify an environment name") exit 1 end edit_object(Chef::Environment, env_name) end end end end chef-11.8.2/lib/chef/knife/node_edit.rb0000644000004100000410000000341612254362222017572 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class NodeEdit < Knife deps do require 'chef/node' require 'chef/json_compat' require 'chef/knife/core/node_editor' end banner "knife node edit NODE (options)" option :all_attributes, :short => "-a", :long => "--all", :boolean => true, :description => "Display all attributes when editing" def run if node_name.nil? show_usage ui.fatal("You must specify a node name") exit 1 end updated_node = node_editor.edit_node if updated_values = node_editor.updated? ui.info "Saving updated #{updated_values.join(', ')} on node #{node.name}" updated_node.save else ui.info "Node not updated, skipping node save" end end def node_name @node_name ||= @name_args[0] end def node_editor @node_editor ||= Knife::NodeEditor.new(node, ui, config) end def node @node ||= Chef::Node.load(node_name) end end end end chef-11.8.2/lib/chef/knife/client_bulk_delete.rb0000644000004100000410000000351712254362222021457 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class ClientBulkDelete < Knife deps do require 'chef/api_client' require 'chef/json_compat' end banner "knife client bulk delete REGEX (options)" def run if name_args.length < 1 ui.fatal("You must supply a regular expression to match the results against") exit 42 end all_clients = Chef::ApiClient.list(true) matcher = /#{name_args[0]}/ clients_to_delete = {} all_clients.each do |name, client| next unless name =~ matcher clients_to_delete[client.name] = client end if clients_to_delete.empty? ui.info "No clients match the expression /#{name_args[0]}/" exit 0 end ui.msg("The following clients will be deleted:") ui.msg("") ui.msg(ui.list(clients_to_delete.keys.sort, :columns_down)) ui.msg("") ui.confirm("Are you sure you want to delete these clients") clients_to_delete.sort.each do |name, client| client.destroy ui.msg("Deleted client #{name}") end end end end end chef-11.8.2/lib/chef/knife/data_bag_edit.rb0000644000004100000410000000543112254362222020366 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Seth Falcon () # Copyright:: Copyright (c) 2009-2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class DataBagEdit < Knife deps do require 'chef/data_bag_item' require 'chef/encrypted_data_bag_item' end banner "knife data bag edit BAG ITEM (options)" category "data bag" option :secret, :short => "-s SECRET", :long => "--secret ", :description => "The secret key to use to encrypt data bag item values", :proc => Proc.new { |s| Chef::Config[:knife][:secret] = s } option :secret_file, :long => "--secret-file SECRET_FILE", :description => "A file containing the secret key to use to encrypt data bag item values", :proc => Proc.new { |sf| Chef::Config[:knife][:secret_file] = sf } def read_secret if config[:secret] config[:secret] else Chef::EncryptedDataBagItem.load_secret(config[:secret_file]) end end def use_encryption if config[:secret] && config[:secret_file] stdout.puts "please specify only one of --secret, --secret-file" exit(1) end config[:secret] || config[:secret_file] end def load_item(bag, item_name) item = Chef::DataBagItem.load(bag, item_name) if use_encryption Chef::EncryptedDataBagItem.new(item, read_secret).to_hash else item end end def edit_item(item) output = edit_data(item) if use_encryption Chef::EncryptedDataBagItem.encrypt_data_bag_item(output, read_secret) else output end end def run if @name_args.length != 2 stdout.puts "You must supply the data bag and an item to edit!" stdout.puts opt_parser exit 1 end item = load_item(@name_args[0], @name_args[1]) output = edit_item(item) rest.put_rest("data/#{@name_args[0]}/#{@name_args[1]}", output) stdout.puts("Saved data_bag_item[#{@name_args[1]}]") ui.output(output) if config[:print_after] end end end end chef-11.8.2/lib/chef/knife/node_run_list_set.rb0000644000004100000410000000353212254362222021356 0ustar www-datawww-data# # Author:: Mike Fiedler () # Copyright:: Copyright (c) 2013 Mike Fiedler # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class NodeRunListSet < Knife deps do require 'chef/node' require 'chef/json_compat' end banner "knife node run_list set NODE ENTRIES (options)" def run if @name_args.size < 2 ui.fatal "You must supply both a node name and a run list." show_usage exit 1 elsif @name_args.size > 2 # Check for nested lists and create a single plain one entries = @name_args[1..-1].map do |entry| entry.split(',').map { |e| e.strip } end.flatten else # Convert to array and remove the extra spaces entries = @name_args[1].split(',').map { |e| e.strip } end node = Chef::Node.load(@name_args[0]) set_run_list(node, entries) node.save config[:run_list] = true output(format_for_display(node)) end # Clears out any existing run_list_items and sets them to the # specified entries def set_run_list(node, entries) node.run_list.run_list_items.clear entries.each { |e| node.run_list << e } end end end end chef-11.8.2/lib/chef/knife/upload.rb0000644000004100000410000000373612254362222017131 0ustar www-datawww-datarequire 'chef/chef_fs/knife' class Chef class Knife class Upload < Chef::ChefFS::Knife banner "knife upload PATTERNS" category "path-based" deps do require 'chef/chef_fs/command_line' end option :recurse, :long => '--[no-]recurse', :boolean => true, :default => true, :description => "List directories recursively." option :purge, :long => '--[no-]purge', :boolean => true, :default => false, :description => "Delete matching local files and directories that do not exist remotely." option :force, :long => '--[no-]force', :boolean => true, :default => false, :description => "Force upload of files even if they match (quicker for many files). Will overwrite frozen cookbooks." option :freeze, :long => '--[no-]freeze', :boolean => true, :default => false, :description => "Freeze cookbooks that get uploaded." option :dry_run, :long => '--dry-run', :short => '-n', :boolean => true, :default => false, :description => "Don't take action, only print what would happen" option :diff, :long => '--[no-]diff', :boolean => true, :default => true, :description => 'Turn off to avoid uploading existing files; only new (and possibly deleted) files with --no-diff' def run if name_args.length == 0 show_usage ui.fatal("Must specify at least one argument. If you want to upload everything in this directory, type \"knife upload .\"") exit 1 end error = false pattern_args.each do |pattern| if Chef::ChefFS::FileSystem.copy_to(pattern, local_fs, chef_fs, config[:recurse] ? nil : 1, config, ui, proc { |entry| format_path(entry) }) error = true end end if error exit 1 end end end end end chef-11.8.2/lib/chef/knife/tag_delete.rb0000644000004100000410000000331112254362222017727 0ustar www-datawww-data# # Author:: Ryan Davis () # Author:: Daniel DeLeo () # Author:: Nuo Yan () # Copyright:: Copyright (c) 2011 Ryan Davis and Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class TagDelete < Knife deps do require 'chef/node' end banner "knife tag delete NODE TAG ..." def run name = @name_args[0] tags = @name_args[1..-1] if name.nil? || tags.nil? || tags.empty? show_usage ui.fatal("You must specify a node name and at least one tag.") exit 1 end node = Chef::Node.load name deleted_tags = Array.new tags.each do |tag| unless node.tags.delete(tag).nil? deleted_tags << tag end end node.save message = if deleted_tags.empty? "Nothing has changed. The tags requested to be deleted do not exist." else "Deleted tags #{deleted_tags.join(", ")} for node #{name}." end ui.info(message) end end end end chef-11.8.2/lib/chef/knife/node_run_list_add.rb0000644000004100000410000000402712254362222021313 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class NodeRunListAdd < Knife deps do require 'chef/node' require 'chef/json_compat' end banner "knife node run_list add [NODE] [ENTRY[,ENTRY]] (options)" option :after, :short => "-a ITEM", :long => "--after ITEM", :description => "Place the ENTRY in the run list after ITEM" def run node = Chef::Node.load(@name_args[0]) if @name_args.size > 2 # Check for nested lists and create a single plain one entries = @name_args[1..-1].map do |entry| entry.split(',').map { |e| e.strip } end.flatten else # Convert to array and remove the extra spaces entries = @name_args[1].split(',').map { |e| e.strip } end add_to_run_list(node, entries, config[:after]) node.save config[:run_list] = true output(format_for_display(node)) end def add_to_run_list(node, entries, after=nil) if after nlist = [] node.run_list.each do |entry| nlist << entry if entry == after entries.each { |e| nlist << e } end end node.run_list.reset!(nlist) else entries.each { |e| node.run_list << e } end end end end end chef-11.8.2/lib/chef/knife/node_list.rb0000644000004100000410000000226512254362222017621 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class NodeList < Knife deps do require 'chef/node' require 'chef/json_compat' end banner "knife node list (options)" option :with_uri, :short => "-w", :long => "--with-uri", :description => "Show corresponding URIs" def run env = Chef::Config[:environment] output(format_list_for_display( env ? Chef::Node.list_by_environment(env) : Chef::Node.list )) end end end end chef-11.8.2/lib/chef/knife/help.rb0000644000004100000410000000635212254362222016572 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Knife class Help < Chef::Knife banner "knife help [list|TOPIC]" def run if name_args.empty? ui.info "Usage: knife SUBCOMMAND (options)" ui.msg "" # This command is atypical, the user is likely not interested in usage of # this command, but knife in general. So hack the banner. opt_parser.banner = "General Knife Options:" ui.msg opt_parser.to_s ui.msg "" ui.info "For further help:" ui.info(<<-MOAR_HELP) knife help list list help topics knife help knife show general knife help knife help TOPIC display the manual for TOPIC knife SUBCOMMAND --help show the options for a command MOAR_HELP exit 1 else @query = name_args.join('-') end case @query when 'topics', 'list' print_help_topics exit 1 when 'intro', 'knife' @topic = 'knife' else @topic = find_manpages_for_query(@query) end manpage_path = find_manpage_path(@topic) exec "man #{manpage_path}" end def help_topics # The list of help topics is generated by a rake task from the available man pages # This constant is provided in help_topics.rb which is automatically required/loaded by the knife subcommand loader. HELP_TOPICS end def print_help_topics ui.info "Available help topics are: " help_topics.collect {|t| t.gsub(/knife-/, '') }.sort.each do |topic| ui.msg " #{topic}" end end def find_manpages_for_query(query) possibilities = help_topics.select do |manpage| ::File.fnmatch("knife-#{query}*", manpage) || ::File.fnmatch("#{query}*", manpage) end if possibilities.empty? ui.error "No help found for '#{query}'" ui.msg "" print_help_topics exit 1 elsif possibilities.size == 1 possibilities.first else ui.info "Multiple help topics match your query. Pick one:" ui.highline.choose(*possibilities) end end def find_manpage_path(topic) if ::File.exists?(::File.expand_path("../distro/common/man/man1/#{topic}.1", CHEF_ROOT)) # If we've provided the man page in the gem, give that return ::File.expand_path("../distro/common/man/man1/#{topic}.1", CHEF_ROOT) else # Otherwise, we'll just be using MANPATH topic end end end end end chef-11.8.2/lib/chef/knife/client_list.rb0000644000004100000410000000215212254362222020145 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class ClientList < Knife deps do require 'chef/api_client' require 'chef/json_compat' end banner "knife client list (options)" option :with_uri, :short => "-w", :long => "--with-uri", :description => "Show corresponding URIs" def run output(format_list_for_display(Chef::ApiClient.list)) end end end end chef-11.8.2/lib/chef/knife/cookbook_site_search.rb0000644000004100000410000000276112254362222022021 0ustar www-datawww-data# Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class CookbookSiteSearch < Knife banner "knife cookbook site search QUERY (options)" category "cookbook site" def run output(search_cookbook(name_args[0])) end def search_cookbook(query, items=10, start=0, cookbook_collection={}) cookbooks_url = "http://cookbooks.opscode.com/api/v1/search?q=#{query}&items=#{items}&start=#{start}" cr = noauth_rest.get_rest(cookbooks_url) cr["items"].each do |cookbook| cookbook_collection[cookbook["cookbook_name"]] = cookbook end new_start = start + cr["items"].length if new_start < cr["total"] search_cookbook(query, items, new_start, cookbook_collection) else cookbook_collection end end end end end chef-11.8.2/lib/chef/knife/edit.rb0000644000004100000410000000421112254362222016557 0ustar www-datawww-datarequire 'chef/chef_fs/knife' class Chef class Knife class Edit < Chef::ChefFS::Knife banner "knife edit [PATTERN1 ... PATTERNn]" category "path-based" deps do require 'chef/chef_fs/file_system' require 'chef/chef_fs/file_system/not_found_error' end option :local, :long => '--local', :boolean => true, :description => "Show local files instead of remote" def run # Get the matches (recursively) error = false pattern_args.each do |pattern| Chef::ChefFS::FileSystem.list(config[:local] ? local_fs : chef_fs, pattern).each do |result| if result.dir? ui.error "#{format_path(result)}: is a directory" if pattern.exact_path error = true else begin new_value = edit_text(result.read, File.extname(result.name)) if new_value result.write(new_value) output "Updated #{format_path(result)}" else output "#{format_path(result)} unchanged!" end rescue Chef::ChefFS::FileSystem::OperationNotAllowedError => e ui.error "#{format_path(e.entry)}: #{e.reason}." error = true rescue Chef::ChefFS::FileSystem::NotFoundError => e ui.error "#{format_path(e.entry)}: No such file or directory" error = true end end end end if error exit 1 end end def edit_text(text, extension) if (!config[:disable_editing]) Tempfile.open([ 'knife-edit-', extension ]) do |file| # Write the text to a temporary file file.write(text) file.close # Let the user edit the temporary file if !system("#{config[:editor]} #{file.path}") raise "Please set EDITOR environment variable" end result_text = IO.read(file.path) return result_text if result_text != text end end end end end end chef-11.8.2/lib/chef/knife/configure_client.rb0000644000004100000410000000322712254362222021157 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class ConfigureClient < Knife banner "knife configure client DIRECTORY" def run unless @config_dir = @name_args[0] ui.fatal "You must provide the directory to put the files in" show_usage exit(1) end ui.info("Creating client configuration") FileUtils.mkdir_p(@config_dir) ui.info("Writing client.rb") File.open(File.join(@config_dir, "client.rb"), "w") do |file| file.puts('log_level :info') file.puts('log_location STDOUT') file.puts("chef_server_url '#{Chef::Config[:chef_server_url]}'") file.puts("validation_client_name '#{Chef::Config[:validation_client_name]}'") end ui.info("Writing validation.pem") File.open(File.join(@config_dir, 'validation.pem'), "w") do |validation| validation.puts(IO.read(Chef::Config[:validation_key])) end end end end end chef-11.8.2/lib/chef/knife/client_create.rb0000644000004100000410000000415312254362222020440 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class ClientCreate < Knife deps do require 'chef/api_client' require 'chef/json_compat' end option :file, :short => "-f FILE", :long => "--file FILE", :description => "Write the key to a file" option :admin, :short => "-a", :long => "--admin", :description => "Create the client as an admin", :boolean => true banner "knife client create CLIENT (options)" def run @client_name = @name_args[0] if @client_name.nil? show_usage ui.fatal("You must specify a client name") exit 1 end client = Chef::ApiClient.new client.name(@client_name) client.admin(config[:admin]) output = edit_data(client) # Chef::ApiClient.save will try to create a client and if it exists will update it instead silently client = output.save # We only get a private_key on client creation, not on client update. if client['private_key'] ui.info("Created #{output}") if config[:file] File.open(config[:file], "w") do |f| f.print(client['private_key']) end else puts client['private_key'] end else ui.error "Client '#{client['name']}' already exists" exit 1 end end end end end chef-11.8.2/lib/chef/knife/cookbook_download.rb0000644000004100000410000001071512254362222021335 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Walters () # Copyright:: Copyright (c) 2009, 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class CookbookDownload < Knife attr_reader :version attr_accessor :cookbook_name deps do require 'chef/cookbook_version' end banner "knife cookbook download COOKBOOK [VERSION] (options)" option :latest, :short => "-N", :long => "--latest", :description => "The version of the cookbook to download", :boolean => true option :download_directory, :short => "-d DOWNLOAD_DIRECTORY", :long => "--dir DOWNLOAD_DIRECTORY", :description => "The directory to download the cookbook into", :default => Dir.pwd option :force, :short => "-f", :long => "--force", :description => "Force download over the download directory if it exists" # TODO: tim/cw: 5-23-2010: need to implement knife-side # specificity for downloads - need to implement --platform and # --fqdn here def run @cookbook_name, @version = @name_args if @cookbook_name.nil? show_usage ui.fatal("You must specify a cookbook name") exit 1 elsif @version.nil? @version = determine_version if @version.nil? ui.fatal("No such cookbook found") exit 1 end end ui.info("Downloading #{@cookbook_name} cookbook version #{@version}") cookbook = rest.get_rest("cookbooks/#{@cookbook_name}/#{@version}") manifest = cookbook.manifest basedir = File.join(config[:download_directory], "#{@cookbook_name}-#{cookbook.version}") if File.exists?(basedir) if config[:force] Chef::Log.debug("Deleting #{basedir}") FileUtils.rm_rf(basedir) else ui.fatal("Directory #{basedir} exists, use --force to overwrite") exit end end Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |segment| next unless manifest.has_key?(segment) ui.info("Downloading #{segment}") manifest[segment].each do |segment_file| dest = File.join(basedir, segment_file['path'].gsub('/', File::SEPARATOR)) Chef::Log.debug("Downloading #{segment_file['path']} to #{dest}") FileUtils.mkdir_p(File.dirname(dest)) rest.sign_on_redirect = false tempfile = rest.get_rest(segment_file['url'], true) FileUtils.mv(tempfile.path, dest) end end ui.info("Cookbook downloaded to #{basedir}") end def determine_version if available_versions.nil? nil elsif available_versions.size == 1 @version = available_versions.first elsif config[:latest] @version = available_versions.last else ask_which_version end end def available_versions @available_versions ||= begin versions = Chef::CookbookVersion.available_versions(@cookbook_name) unless versions.nil? versions.map! { |version| Chef::Version.new(version) } versions.sort! end versions end @available_versions end def ask_which_version question = "Which version do you want to download?\n" valid_responses = {} available_versions.each_with_index do |version, index| valid_responses[(index + 1).to_s] = version question << "#{index + 1}. #{@cookbook_name} #{version}\n" end question += "\n" response = ask_question(question).strip unless @version = valid_responses[response] ui.error("'#{response}' is not a valid value.") exit(1) end @version end end end end chef-11.8.2/lib/chef/knife/environment_delete.rb0000644000004100000410000000225012254362222021521 0ustar www-datawww-data# # Author:: Stephen Delano () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class EnvironmentDelete < Knife deps do require 'chef/environment' require 'chef/json_compat' end banner "knife environment delete ENVIRONMENT (options)" def run env_name = @name_args[0] if env_name.nil? show_usage ui.fatal("You must specify an environment name") exit 1 end delete_object(Chef::Environment, env_name) end end end end chef-11.8.2/lib/chef/knife/data_bag_create.rb0000644000004100000410000000574712254362222020716 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Seth Falcon () # Copyright:: Copyright (c) 2009-2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class DataBagCreate < Knife deps do require 'chef/data_bag' require 'chef/encrypted_data_bag_item' end banner "knife data bag create BAG [ITEM] (options)" category "data bag" option :secret, :short => "-s SECRET", :long => "--secret ", :description => "The secret key to use to encrypt data bag item values", :proc => Proc.new { |s| Chef::Config[:knife][:secret] = s } option :secret_file, :long => "--secret-file SECRET_FILE", :description => "A file containing the secret key to use to encrypt data bag item values", :proc => Proc.new { |sf| Chef::Config[:knife][:secret_file] = sf } def read_secret if config[:secret] config[:secret] else Chef::EncryptedDataBagItem.load_secret(config[:secret_file]) end end def use_encryption if config[:secret] && config[:secret_file] ui.fatal("please specify only one of --secret, --secret-file") exit(1) end config[:secret] || config[:secret_file] end def run @data_bag_name, @data_bag_item_name = @name_args if @data_bag_name.nil? show_usage ui.fatal("You must specify a data bag name") exit 1 end # create the data bag begin rest.post_rest("data", { "name" => @data_bag_name }) ui.info("Created data_bag[#{@data_bag_name}]") rescue Net::HTTPServerException => e raise unless e.to_s =~ /^409/ ui.info("Data bag #{@data_bag_name} already exists") end # if an item is specified, create it, as well if @data_bag_item_name create_object({ "id" => @data_bag_item_name }, "data_bag_item[#{@data_bag_item_name}]") do |output| item = Chef::DataBagItem.from_hash( if use_encryption Chef::EncryptedDataBagItem.encrypt_data_bag_item(output, read_secret) else output end) item.data_bag(@data_bag_name) rest.post_rest("data/#{@data_bag_name}", item) end end end end end end chef-11.8.2/lib/chef/knife/user_list.rb0000644000004100000410000000213612254362222017647 0ustar www-datawww-data# # Author:: Steven Danna () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class UserList < Knife deps do require 'chef/user' require 'chef/json_compat' end banner "knife user list (options)" option :with_uri, :short => "-w", :long => "--with-uri", :description => "Show corresponding URIs" def run output(format_list_for_display(Chef::User.list)) end end end end chef-11.8.2/lib/chef/knife/list.rb0000644000004100000410000001155012254362222016611 0ustar www-datawww-datarequire 'chef/chef_fs/knife' class Chef class Knife class List < Chef::ChefFS::Knife banner "knife list [-dfR1p] [PATTERN1 ... PATTERNn]" category "path-based" deps do require 'chef/chef_fs/file_system' require 'highline' end option :recursive, :short => '-R', :boolean => true, :description => "List directories recursively" option :bare_directories, :short => '-d', :boolean => true, :description => "When directories match the pattern, do not show the directories' children" option :local, :long => '--local', :boolean => true, :description => "List local directory instead of remote" option :flat, :short => '-f', :long => '--flat', :boolean => true, :description => "Show a list of filenames rather than the prettified ls-like output normally produced" option :one_column, :short => '-1', :boolean => true, :description => "Show only one column of results" option :trailing_slashes, :short => '-p', :boolean => true, :description => "Show trailing slashes after directories" attr_accessor :exit_code def run patterns = name_args.length == 0 ? [""] : name_args # Get the matches (recursively) all_results = parallelize(pattern_args_from(patterns), :flatten => true) do |pattern| pattern_results = Chef::ChefFS::FileSystem.list(config[:local] ? local_fs : chef_fs, pattern) if pattern_results.first && !pattern_results.first.exists? && pattern.exact_path ui.error "#{format_path(pattern_results.first)}: No such file or directory" self.exit_code = 1 end pattern_results end # Process directories if !config[:bare_directories] dir_results = parallelize(all_results.select { |result| result.dir? }, :flatten => true) do |result| add_dir_result(result) end.to_a else dir_results = [] end # Process all other results results = all_results.select { |result| result.exists? && (!result.dir? || config[:bare_directories]) }.to_a # Flatten out directory results if necessary if config[:flat] dir_results.each do |result, children| results += children end dir_results = [] end # Sort by path for happy output results = results.sort_by { |result| result.path } dir_results = dir_results.sort_by { |result| result[0].path } # Print! if results.length == 0 && dir_results.length == 1 results = dir_results[0][1] dir_results = [] end print_result_paths results printed_something = results.length > 0 dir_results.each do |result, children| if printed_something output "" else printed_something = true end output "#{format_path(result)}:" print_results(children.map { |result| maybe_add_slash(result.name, result.dir?) }.sort, "") end exit self.exit_code if self.exit_code end def add_dir_result(result) begin children = result.children.sort_by { |child| child.name } rescue Chef::ChefFS::FileSystem::NotFoundError => e ui.error "#{format_path(e.entry)}: No such file or directory" return [] end result = [ [ result, children ] ] if config[:recursive] child_dirs = children.select { |child| child.dir? } result += parallelize(child_dirs, :flatten => true) { |child| add_dir_result(child) }.to_a end result end def print_result_paths(results, indent = "") print_results(results.map { |result| maybe_add_slash(format_path(result), result.dir?) }, indent) end def print_results(results, indent) return if results.length == 0 print_space = results.map { |result| result.length }.max + 2 if config[:one_column] || !stdout.isatty columns = 0 else columns = HighLine::SystemExtensions.terminal_size[0] end current_line = '' results.each do |result| if current_line.length > 0 && current_line.length + print_space > columns output current_line.rstrip current_line = '' end if current_line.length == 0 current_line << indent end current_line << result current_line << (' ' * (print_space - result.length)) end output current_line.rstrip if current_line.length > 0 end def maybe_add_slash(path, is_dir) if config[:trailing_slashes] && is_dir "#{path}/" else path end end end end end chef-11.8.2/lib/chef/knife/raw.rb0000644000004100000410000000533112254362222016427 0ustar www-datawww-datarequire 'chef/knife' class Chef class Knife class Raw < Chef::Knife banner "knife raw REQUEST_PATH" deps do require 'chef/json_compat' require 'chef/config' require 'chef/http' require 'chef/http/authenticator' require 'chef/http/cookie_manager' require 'chef/http/decompressor' require 'chef/http/json_output' end option :method, :long => '--method METHOD', :short => '-m METHOD', :default => "GET", :description => "Request method (GET, POST, PUT or DELETE). Default: GET" option :pretty, :long => '--[no-]pretty', :boolean => true, :default => true, :description => "Pretty-print JSON output. Default: true" option :input, :long => '--input FILE', :short => '-i FILE', :description => "Name of file to use for PUT or POST" class RawInputServerAPI < Chef::HTTP def initialize(options = {}) options[:client_name] ||= Chef::Config[:node_name] options[:signing_key_filename] ||= Chef::Config[:client_key] super(Chef::Config[:chef_server_url], options) end use Chef::HTTP::JSONOutput use Chef::HTTP::CookieManager use Chef::HTTP::Decompressor use Chef::HTTP::Authenticator end def run if name_args.length == 0 show_usage ui.fatal("You must provide the path you want to hit on the server") exit(1) elsif name_args.length > 1 show_usage ui.fatal("Only one path accepted for knife raw") exit(1) end path = name_args[0] data = false if config[:input] data = IO.read(config[:input]) end begin method = config[:method].to_sym if config[:pretty] chef_rest = RawInputServerAPI.new result = chef_rest.request(method, name_args[0], {'Content-Type' => 'application/json'}, data) unless result.is_a?(String) result = Chef::JSONCompat.to_json_pretty(result) end else chef_rest = RawInputServerAPI.new(:raw_output => true) result = chef_rest.request(method, name_args[0], {'Content-Type' => 'application/json'}, data) end output result rescue Timeout::Error => e ui.error "Server timeout" exit 1 rescue Net::HTTPServerException => e ui.error "Server responded with error #{e.response.code} \"#{e.response.message}\"" ui.error "Error Body: #{e.response.body}" if e.response.body && e.response.body != '' exit 1 end end end # class Raw end end chef-11.8.2/lib/chef/knife/node_delete.rb0000644000004100000410000000217612254362222020111 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class NodeDelete < Knife deps do require 'chef/node' require 'chef/json_compat' end banner "knife node delete NODE (options)" def run @node_name = @name_args[0] if @node_name.nil? show_usage ui.fatal("You must specify a node name") exit 1 end delete_object(Chef::Node, @node_name) end end end end chef-11.8.2/lib/chef/knife/environment_show.rb0000644000004100000410000000237712254362222021251 0ustar www-datawww-data# # Author:: Stephen Delano () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class EnvironmentShow < Knife include Knife::Core::MultiAttributeReturnOption deps do require 'chef/environment' require 'chef/json_compat' end banner "knife environment show ENVIRONMENT (options)" def run env_name = @name_args[0] if env_name.nil? show_usage ui.fatal("You must specify an environment name") exit 1 end env = Chef::Environment.load(env_name) output(format_for_display(env)) end end end end chef-11.8.2/lib/chef/knife/role_list.rb0000644000004100000410000000213412254362222017630 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class RoleList < Knife deps do require 'chef/node' require 'chef/json_compat' end banner "knife role list (options)" option :with_uri, :short => "-w", :long => "--with-uri", :description => "Show corresponding URIs" def run output(format_list_for_display(Chef::Role.list)) end end end end chef-11.8.2/lib/chef/knife/client_reregister.rb0000644000004100000410000000304712254362222021351 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class ClientReregister < Knife deps do require 'chef/api_client' require 'chef/json_compat' end banner "knife client reregister CLIENT (options)" option :file, :short => "-f FILE", :long => "--file FILE", :description => "Write the key to a file" def run @client_name = @name_args[0] if @client_name.nil? show_usage ui.fatal("You must specify a client name") exit 1 end client = Chef::ApiClient.reregister(@client_name) Chef::Log.debug("Updated client data: #{client.inspect}") key = client.private_key if config[:file] File.open(config[:file], "w") do |f| f.print(key) end else ui.msg key end end end end end chef-11.8.2/lib/chef/knife/download.rb0000644000004100000410000000400612254362222017443 0ustar www-datawww-datarequire 'chef/chef_fs/knife' class Chef class Knife class Download < Chef::ChefFS::Knife banner "knife download PATTERNS" category "path-based" deps do require 'chef/chef_fs/command_line' end option :recurse, :long => '--[no-]recurse', :boolean => true, :default => true, :description => "List directories recursively." option :purge, :long => '--[no-]purge', :boolean => true, :default => false, :description => "Delete matching local files and directories that do not exist remotely." option :force, :long => '--[no-]force', :boolean => true, :default => false, :description => "Force upload of files even if they match (quicker and harmless, but doesn't print out what it changed)" option :dry_run, :long => '--dry-run', :short => '-n', :boolean => true, :default => false, :description => "Don't take action, only print what would happen" option :diff, :long => '--[no-]diff', :boolean => true, :default => true, :description => 'Turn off to avoid uploading existing files; only new (and possibly deleted) files with --no-diff' option :cookbook_version, :long => '--cookbook-version VERSION', :description => 'Version of cookbook to download (if there are multiple versions and cookbook_versions is false)' def run if name_args.length == 0 show_usage ui.fatal("Must specify at least one argument. If you want to download everything in this directory, type \"knife download .\"") exit 1 end error = false pattern_args.each do |pattern| if Chef::ChefFS::FileSystem.copy_to(pattern, chef_fs, local_fs, config[:recurse] ? nil : 1, config, ui, proc { |entry| format_path(entry) }) error = true end end if error exit 1 end end end end end chef-11.8.2/lib/chef/knife/delete.rb0000644000004100000410000000627112254362222017104 0ustar www-datawww-datarequire 'chef/chef_fs/knife' class Chef class Knife class Delete < Chef::ChefFS::Knife banner "knife delete [PATTERN1 ... PATTERNn]" category "path-based" deps do require 'chef/chef_fs/file_system' end option :recurse, :short => '-r', :long => '--[no-]recurse', :boolean => true, :default => false, :description => "Delete directories recursively." option :both, :long => '--both', :boolean => true, :default => false, :description => "Delete both the local and remote copies." option :local, :long => '--local', :boolean => true, :default => false, :description => "Delete the local copy (leave the remote copy)." def run if name_args.length == 0 show_usage ui.fatal("Must specify at least one argument. If you want to delete everything in this directory, type \"knife delete --recurse .\"") exit 1 end # Get the matches (recursively) error = false if config[:local] pattern_args.each do |pattern| Chef::ChefFS::FileSystem.list(local_fs, pattern).each do |result| if delete_result(result) error = true end end end elsif config[:both] pattern_args.each do |pattern| Chef::ChefFS::FileSystem.list_pairs(pattern, chef_fs, local_fs).each do |chef_result, local_result| if delete_result(chef_result, local_result) error = true end end end else # Remote only pattern_args.each do |pattern| Chef::ChefFS::FileSystem.list(chef_fs, pattern).each do |result| if delete_result(result) error = true end end end end if error exit 1 end end def format_path_with_root(entry) root = entry.root == chef_fs ? " (remote)" : " (local)" "#{format_path(entry)}#{root}" end def delete_result(*results) deleted_any = false found_any = false error = false results.each do |result| begin result.delete(config[:recurse]) deleted_any = true found_any = true rescue Chef::ChefFS::FileSystem::NotFoundError # This is not an error unless *all* of them were not found rescue Chef::ChefFS::FileSystem::MustDeleteRecursivelyError => e ui.error "#{format_path_with_root(e.entry)} must be deleted recursively! Pass -r to knife delete." found_any = true error = true rescue Chef::ChefFS::FileSystem::OperationNotAllowedError => e ui.error "#{format_path_with_root(e.entry)} #{e.reason}." found_any = true error = true end end if deleted_any output("Deleted #{format_path(results[0])}") elsif !found_any ui.error "#{format_path(results[0])}: No such file or directory" error = true end error end end end end chef-11.8.2/lib/chef/knife/user_edit.rb0000644000004100000410000000262412254362222017623 0ustar www-datawww-data# # Author:: Steven Danna () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class UserEdit < Knife deps do require 'chef/user' require 'chef/json_compat' end banner "knife user edit USER (options)" def run @user_name = @name_args[0] if @user_name.nil? show_usage ui.fatal("You must specify a user name") exit 1 end original_user = Chef::User.load(@user_name).to_hash edited_user = edit_data(original_user) if original_user != edited_user user = Chef::User.from_hash(edited_user) user.update ui.msg("Saved #{user}.") else ui.msg("User unchaged, not saving.") end end end end end chef-11.8.2/lib/chef/knife/cookbook_site_list.rb0000644000004100000410000000347712254362222021534 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class CookbookSiteList < Knife banner "knife cookbook site list (options)" category "cookbook site" option :with_uri, :short => "-w", :long => "--with-uri", :description => "Show corresponding URIs" def run if config[:with_uri] cookbooks = Hash.new get_cookbook_list.each{ |k,v| cookbooks[k] = v['cookbook'] } ui.output(format_for_display(cookbooks)) else ui.msg(ui.list(get_cookbook_list.keys.sort, :columns_down)) end end def get_cookbook_list(items=10, start=0, cookbook_collection={}) cookbooks_url = "http://cookbooks.opscode.com/api/v1/cookbooks?items=#{items}&start=#{start}" cr = noauth_rest.get_rest(cookbooks_url) cr["items"].each do |cookbook| cookbook_collection[cookbook["cookbook_name"]] = cookbook end new_start = start + cr["items"].length if new_start < cr["total"] get_cookbook_list(items, new_start, cookbook_collection) else cookbook_collection end end end end end chef-11.8.2/lib/chef/knife/role_edit.rb0000644000004100000410000000217412254362222017606 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class RoleEdit < Knife deps do require 'chef/role' require 'chef/json_compat' end banner "knife role edit ROLE (options)" def run @role_name = @name_args[0] if @role_name.nil? show_usage ui.fatal("You must specify a role name") exit 1 end ui.edit_object(Chef::Role, @role_name) end end end end chef-11.8.2/lib/chef/knife/cookbook_list.rb0000644000004100000410000000277012254362222020503 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Nuo Yan () # Copyright:: Copyright (c) 2009, 2010, 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class CookbookList < Knife banner "knife cookbook list (options)" option :with_uri, :short => "-w", :long => "--with-uri", :description => "Show corresponding URIs" option :all_versions, :short => "-a", :long => "--all", :description => "Show all available versions." def run env = config[:environment] num_versions = config[:all_versions] ? "num_versions=all" : "num_versions=1" api_endpoint = env ? "/environments/#{env}/cookbooks?#{num_versions}" : "/cookbooks?#{num_versions}" cookbook_versions = rest.get_rest(api_endpoint) ui.output(format_cookbook_list_for_display(cookbook_versions)) end end end end chef-11.8.2/lib/chef/knife/xargs.rb0000644000004100000410000002121412254362222016760 0ustar www-datawww-datarequire 'chef/chef_fs/knife' class Chef class Knife class Xargs < Chef::ChefFS::Knife banner "knife xargs [COMMAND]" category "path-based" deps do require 'chef/chef_fs/file_system' require 'chef/chef_fs/file_system/not_found_error' end # TODO modify to remote-only / local-only pattern (more like delete) option :local, :long => '--local', :boolean => true, :description => "Xargs local files instead of remote" option :patterns, :long => '--pattern [PATTERN]', :short => '-p [PATTERN]', :description => "Pattern on command line (if these are not specified, a list of patterns is expected on standard input). Multiple patterns may be passed in this way.", :arg_arity => [1,-1] option :diff, :long => '--[no-]diff', :default => true, :boolean => true, :description => "Whether to show a diff when files change (default: true)" option :dry_run, :long => '--dry-run', :boolean => true, :description => "Prevents changes from actually being uploaded to the server." option :force, :long => '--[no-]force', :boolean => true, :default => false, :description => "Force upload of files even if they are not changed (quicker and harmless, but doesn't print out what it changed)" option :replace_first, :long => '--replace-first REPLACESTR', :short => '-J REPLACESTR', :description => "String to replace with filenames. -J will only replace the FIRST occurrence of the replacement string." option :replace_all, :long => '--replace REPLACESTR', :short => '-I REPLACESTR', :description => "String to replace with filenames. -I will replace ALL occurrence of the replacement string." option :max_arguments_per_command, :long => '--max-args MAXARGS', :short => '-n MAXARGS', :description => "Maximum number of arguments per command line." option :max_command_line, :long => '--max-chars LENGTH', :short => '-s LENGTH', :description => "Maximum size of command line, in characters" option :verbose_commands, :short => '-t', :description => "Print command to be run on the command line" option :null_separator, :short => '-0', :boolean => true, :description => "Use the NULL character (\0) as a separator, instead of whitespace" def run error = false # Get the matches (recursively) files = [] pattern_args_from(get_patterns).each do |pattern| Chef::ChefFS::FileSystem.list(config[:local] ? local_fs : chef_fs, pattern).each do |result| if result.dir? # TODO option to include directories ui.warn "#{format_path(result)}: is a directory. Will not run #{command} on it." else files << result ran = false # If the command would be bigger than max command line, back it off a bit # and run a slightly smaller command (with one less arg) if config[:max_command_line] command, tempfiles = create_command(files) begin if command.length > config[:max_command_line].to_i if files.length > 1 command, tempfiles_minus_one = create_command(files[0..-2]) begin error = true if xargs_files(command, tempfiles_minus_one) files = [ files[-1] ] ran = true ensure destroy_tempfiles(tempfiles) end else error = true if xargs_files(command, tempfiles) files = [ ] ran = true end end ensure destroy_tempfiles(tempfiles) end end # If the command has hit the limit for the # of arguments, run it if !ran && config[:max_arguments_per_command] && files.size >= config[:max_arguments_per_command].to_i command, tempfiles = create_command(files) begin error = true if xargs_files(command, tempfiles) files = [] ran = true ensure destroy_tempfiles(tempfiles) end end end end end # Any leftovers commands shall be run if files.size > 0 command, tempfiles = create_command(files) begin error = true if xargs_files(command, tempfiles) ensure destroy_tempfiles(tempfiles) end end if error exit 1 end end def get_patterns if config[:patterns] [ config[:patterns] ].flatten elsif config[:null_separator] stdin.binmode stdin.read.split("\000") else stdin.read.split(/\s+/) end end def create_command(files) command = name_args.join(' ') # Create the (empty) tempfiles tempfiles = {} begin # Create the temporary files files.each do |file| tempfile = Tempfile.new(file.name) tempfiles[tempfile] = { :file => file } end rescue destroy_tempfiles(files) raise end # Create the command paths = tempfiles.keys.map { |tempfile| tempfile.path }.join(' ') if config[:replace_all] final_command = command.gsub(config[:replace_all], paths) elsif config[:replace_first] final_command = command.sub(config[:replace_first], paths) else final_command = "#{command} #{paths}" end [final_command, tempfiles] end def destroy_tempfiles(tempfiles) # Unlink the files now that we're done with them tempfiles.keys.each { |tempfile| tempfile.close! } end def xargs_files(command, tempfiles) error = false # Create the temporary files tempfiles.each_pair do |tempfile, file| begin value = file[:file].read file[:value] = value tempfile.open tempfile.write(value) tempfile.close rescue Chef::ChefFS::FileSystem::OperationNotAllowedError => e ui.error "#{format_path(e.entry)}: #{e.reason}." error = true tempfile.close! tempfiles.delete(tempfile) next rescue Chef::ChefFS::FileSystem::NotFoundError => e ui.error "#{format_path(e.entry)}: No such file or directory" error = true tempfile.close! tempfiles.delete(tempfile) next end end return error if error && tempfiles.size == 0 # Run the command if config[:verbose_commands] || Chef::Config[:verbosity] && Chef::Config[:verbosity] >= 1 output sub_filenames(command, tempfiles) end command_output = `#{command}` command_output = sub_filenames(command_output, tempfiles) stdout.write command_output # Check if the output is different tempfiles.each_pair do |tempfile, file| # Read the new output new_value = IO.binread(tempfile.path) # Upload the output if different if config[:force] || new_value != file[:value] if config[:dry_run] output "Would update #{format_path(file[:file])}" else file[:file].write(new_value) output "Updated #{format_path(file[:file])}" end end # Print a diff of what was uploaded if config[:diff] && new_value != file[:value] old_file = Tempfile.open(file[:file].name) begin old_file.write(file[:value]) old_file.close diff = `diff -u #{old_file.path} #{tempfile.path}` diff.gsub!(old_file.path, "#{format_path(file[:file])} (old)") diff.gsub!(tempfile.path, "#{format_path(file[:file])} (new)") stdout.write diff ensure old_file.close! end end end error end def sub_filenames(str, tempfiles) tempfiles.each_pair do |tempfile, file| str = str.gsub(tempfile.path, format_path(file[:file])) end str end end end end chef-11.8.2/lib/chef/knife/cookbook_delete.rb0000644000004100000410000001212112254362222020761 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class CookbookDelete < Knife attr_accessor :cookbook_name, :version deps do require 'chef/cookbook_version' end option :all, :short => '-a', :long => '--all', :boolean => true, :description => 'delete all versions' option :purge, :short => '-p', :long => '--purge', :boolean => true, :description => 'Permanently remove files from backing data store' banner "knife cookbook delete COOKBOOK VERSION (options)" def run confirm("Files that are common to multiple cookbooks are shared, so purging the files may disable other cookbooks. Are you sure you want to purge files instead of just deleting the cookbook") if config[:purge] @cookbook_name, @version = name_args if @cookbook_name && @version delete_explicit_version elsif @cookbook_name && config[:all] delete_all_versions elsif @cookbook_name && @version.nil? delete_without_explicit_version elsif @cookbook_name.nil? show_usage ui.fatal("You must provide the name of the cookbook to delete") exit(1) end end def delete_explicit_version delete_object(Chef::CookbookVersion, "#{@cookbook_name} version #{@version}", "cookbook") do delete_request("cookbooks/#{@cookbook_name}/#{@version}") end end def delete_all_versions confirm("Do you really want to delete all versions of #{@cookbook_name}") delete_all_without_confirmation end def delete_all_without_confirmation # look up the available versions again just in case the user # got to the list of versions to delete and selected 'all' # and also a specific version @available_versions = nil Array(available_versions).each do |version| delete_version_without_confirmation(version) end end def delete_without_explicit_version if available_versions.nil? # we already logged an error or 2 about it, so just bail exit(1) elsif available_versions.size == 1 @version = available_versions.first delete_explicit_version else versions_to_delete = ask_which_versions_to_delete delete_versions_without_confirmation(versions_to_delete) end end def available_versions @available_versions ||= rest.get_rest("cookbooks/#{@cookbook_name}").map do |name, url_and_version| url_and_version["versions"].map {|url_by_version| url_by_version["version"]} end.flatten rescue Net::HTTPServerException => e if e.to_s =~ /^404/ ui.error("Cannot find a cookbook named #{@cookbook_name} to delete") nil else raise end end def ask_which_versions_to_delete question = "Which version(s) do you want to delete?\n" valid_responses = {} available_versions.each_with_index do |version, index| valid_responses[(index + 1).to_s] = version question << "#{index + 1}. #{@cookbook_name} #{version}\n" end valid_responses[(available_versions.size + 1).to_s] = :all question << "#{available_versions.size + 1}. All versions\n\n" responses = ask_question(question).split(',').map { |response| response.strip } if responses.empty? ui.error("No versions specified, exiting") exit(1) end versions = responses.map do |response| if version = valid_responses[response] version else ui.error("#{response} is not a valid choice, skipping it") end end versions.compact end def delete_version_without_confirmation(version) object = delete_request("cookbooks/#{@cookbook_name}/#{version}") output(format_for_display(object)) if config[:print_after] ui.info("Deleted cookbook[#{@cookbook_name}][#{version}]") end def delete_versions_without_confirmation(versions) versions.each do |version| if version == :all delete_all_without_confirmation break else delete_version_without_confirmation(version) end end end private def delete_request(path) path += "?purge=true" if config[:purge] rest.delete_rest(path) end end end end chef-11.8.2/lib/chef/knife/cookbook_bulk_delete.rb0000644000004100000410000000507512254362222022010 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009, 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class CookbookBulkDelete < Knife deps do require 'chef/knife/cookbook_delete' require 'chef/cookbook_version' end option :purge, :short => '-p', :long => '--purge', :boolean => true, :description => 'Permanently remove files from backing data store' banner "knife cookbook bulk delete REGEX (options)" def run unless regex_str = @name_args.first ui.fatal("You must supply a regular expression to match the results against") exit 42 end regex = Regexp.new(regex_str) all_cookbooks = Chef::CookbookVersion.list cookbooks_names = all_cookbooks.keys.grep(regex) cookbooks_to_delete = cookbooks_names.inject({}) { |hash, name| hash[name] = all_cookbooks[name];hash } ui.msg "All versions of the following cookbooks will be deleted:" ui.msg "" ui.msg ui.list(cookbooks_to_delete.keys.sort, :columns_down) ui.msg "" unless config[:yes] ui.confirm("Do you really want to delete these cookbooks? (Y/N) ", false) if config[:purge] ui.msg("Files that are common to multiple cookbooks are shared, so purging the files may break other cookbooks.") ui.confirm("Are you sure you want to purge files instead of just deleting the cookbooks") end ui.msg "" end cookbooks_names.each do |cookbook_name| versions = rest.get_rest("cookbooks/#{cookbook_name}")[cookbook_name]["versions"].map {|v| v["version"]}.flatten versions.each do |version| object = rest.delete_rest("cookbooks/#{cookbook_name}/#{version}#{config[:purge] ? "?purge=true" : ""}") ui.info("Deleted cookbook #{cookbook_name.ljust(25)} [#{version}]") end end end end end end chef-11.8.2/lib/chef/knife/search.rb0000644000004100000410000001042212254362222017100 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' require 'chef/knife/core/node_presenter' class Chef class Knife class Search < Knife include Knife::Core::MultiAttributeReturnOption deps do require 'chef/node' require 'chef/environment' require 'chef/api_client' require 'chef/search/query' end include Knife::Core::NodeFormattingOptions banner "knife search INDEX QUERY (options)" option :sort, :short => "-o SORT", :long => "--sort SORT", :description => "The order to sort the results in", :default => nil option :start, :short => "-b ROW", :long => "--start ROW", :description => "The row to start returning results at", :default => 0, :proc => lambda { |i| i.to_i } option :rows, :short => "-R INT", :long => "--rows INT", :description => "The number of rows to return", :default => 1000, :proc => lambda { |i| i.to_i } option :run_list, :short => "-r", :long => "--run-list", :description => "Show only the run list" option :id_only, :short => "-i", :long => "--id-only", :description => "Show only the ID of matching objects" option :query, :short => "-q QUERY", :long => "--query QUERY", :description => "The search query; useful to protect queries starting with -" def run read_cli_args fuzzify_query if @type == 'node' ui.use_presenter Knife::Core::NodePresenter end q = Chef::Search::Query.new escaped_query = URI.escape(@query, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")) result_items = [] result_count = 0 rows = config[:rows] start = config[:start] begin q.search(@type, escaped_query, config[:sort], start, rows) do |item| formatted_item = format_for_display(item) # if formatted_item.respond_to?(:has_key?) && !formatted_item.has_key?('id') # formatted_item['id'] = item.has_key?('id') ? item['id'] : item.name # end result_items << formatted_item result_count += 1 end rescue Net::HTTPServerException => e msg = Chef::JSONCompat.from_json(e.response.body)["error"].first ui.error("knife search failed: #{msg}") exit 1 end if ui.interchange? output({:results => result_count, :rows => result_items}) else ui.msg "#{result_count} items found" ui.msg("\n") result_items.each do |item| output(item) unless config[:id_only] ui.msg("\n") end end end end def read_cli_args if config[:query] if @name_args[1] ui.error "please specify query as an argument or an option via -q, not both" ui.msg opt_parser exit 1 end @type = name_args[0] @query = config[:query] else case name_args.size when 0 ui.error "no query specified" ui.msg opt_parser exit 1 when 1 @type = "node" @query = name_args[0] when 2 @type = name_args[0] @query = name_args[1] end end end def fuzzify_query if @query !~ /:/ @query = "tags:*#{@query}* OR roles:*#{@query}* OR fqdn:*#{@query}* OR addresses:*#{@query}*" end end end end end chef-11.8.2/lib/chef/knife/environment_from_file.rb0000644000004100000410000000430712254362222022226 0ustar www-datawww-data# # Author:: Stephen Delano () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Knife class EnvironmentFromFile < Knife deps do require 'chef/environment' require 'chef/knife/core/object_loader' end banner "knife environment from file FILE [FILE..] (options)" option :all, :short => "-a", :long => "--all", :description => "Upload all environments" def loader @loader ||= Knife::Core::ObjectLoader.new(Chef::Environment, ui) end def environments_path @environments_path ||= "environments" end def find_all_environments loader.find_all_objects("./#{environments_path}/") end def load_all_environments environments = find_all_environments if environments.empty? ui.fatal("Unable to find any environment files in '#{environments_path}'") exit(1) end environments.each do |env| load_environment(env) end end def load_environment(env) updated = loader.load_from("environments", env) updated.save output(format_for_display(updated)) if config[:print_after] ui.info("Updated Environment #{updated.name}") end def run if config[:all] == true load_all_environments else if @name_args[0].nil? show_usage ui.fatal("You must specify a file to load") exit 1 end @name_args.each do |arg| load_environment(arg) end end end end end end chef-11.8.2/lib/chef/knife/recipe_list.rb0000644000004100000410000000171312254362222020140 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef::Knife::RecipeList < Chef::Knife banner "knife recipe list [PATTERN]" def run recipes = rest.get_rest('cookbooks/_recipes') if pattern = @name_args.first recipes = recipes.grep(Regexp.new(pattern)) end output(recipes) end end chef-11.8.2/lib/chef/knife/client_delete.rb0000644000004100000410000000222612254362222020436 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class ClientDelete < Knife deps do require 'chef/api_client' require 'chef/json_compat' end banner "knife client delete CLIENT (options)" def run @client_name = @name_args[0] if @client_name.nil? show_usage ui.fatal("You must specify a client name") exit 1 end delete_object(Chef::ApiClient, @client_name) end end end end chef-11.8.2/lib/chef/knife/user_delete.rb0000644000004100000410000000220012254362222020126 0ustar www-datawww-data# # Author:: Steven Danna () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class UserDelete < Knife deps do require 'chef/user' require 'chef/json_compat' end banner "knife user delete USER (options)" def run @user_name = @name_args[0] if @user_name.nil? show_usage ui.fatal("You must specify a user name") exit 1 end delete_object(Chef::User, @user_name) end end end end chef-11.8.2/lib/chef/knife/index_rebuild.rb0000644000004100000410000001035112254362222020451 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 Daniel DeLeo # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class IndexRebuild < Knife banner "knife index rebuild (options)" option :yes, :short => "-y", :long => "--yes", :boolean => true, :description => "don't bother to ask if I'm sure" def run api_info = grab_api_info if unsupported_version?(api_info) unsupported_server_message(api_info) exit 1 else deprecated_server_message nag output rest.post_rest("/search/reindex", {}) end end def grab_api_info # Since we don't yet have any endpoints that implement an # OPTIONS handler, we need to get our version header # information in a more roundabout way. We'll try to query # for a node we know won't exist; the 404 response that comes # back will give us what we want dummy_node = "knife_index_rebuild_test_#{rand(1000000)}" rest.get_rest("/nodes/#{dummy_node}") rescue Net::HTTPServerException => exception r = exception.response parse_api_info(r) end # Only Chef 11+ servers will have version information in their # headers, and only those servers will lack an API endpoint for # index rebuilding. def unsupported_version?(api_info) !!api_info["version"] end def unsupported_server_message(api_info) ui.error("Rebuilding the index is not available via knife for #{server_type(api_info)}s version 11.0.0 and above.") ui.info("Instead, run the '#{ctl_command(api_info)} reindex' command on the server itself.") end def deprecated_server_message ui.warn("'knife index rebuild' has been removed for Chef 11+ servers. It will continue to work for prior versions, however.") end def nag ui.info("This operation is destructive. Rebuilding the index may take some time.") ui.confirm("Continue") end # Chef 11 (and above) servers return various pieces of # information about the server in an +x-ops-api-info+ header. # This is a +;+ delimited string of key / value pairs, separated # by +=+. # # Given a Net::HTTPResponse object, this method extracts this # information (if present), and returns it as a hash. If no # such header is found, an empty hash is returned. def parse_api_info(response) value = response["x-ops-api-info"] if value kv = value.split(";") kv.inject({}) do |acc, pair| k, v = pair.split("=") acc[k] = v acc end else {} end end # Given an API info hash (see +#parse_api_info(response)+), # return a string describing the kind of server we're # interacting with (based on the +flavor+ field) def server_type(api_info) case api_info["flavor"] when "osc" "Open Source Chef Server" when "opc" "Private Chef Server" else # Generic fallback "Chef Server" end end # Given an API info hash (see +#parse_api_info(response)+), # return the name of the "server-ctl" command for the kind of # server we're interacting with (based on the +flavor+ field) def ctl_command(api_info) case api_info["flavor"] when "osc" "chef-server-ctl" when "opc" "private-chef-ctl" else # Generic fallback "chef-server-ctl" end end end end end chef-11.8.2/lib/chef/knife/environment_create.rb0000644000004100000410000000267112254362222021531 0ustar www-datawww-data# # Author:: Stephen Delano () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class EnvironmentCreate < Knife deps do require 'chef/environment' require 'chef/json_compat' end banner "knife environment create ENVIRONMENT (options)" option :description, :short => "-d DESCRIPTION", :long => "--description DESCRIPTION", :description => "The environment description" def run env_name = @name_args[0] if env_name.nil? show_usage ui.fatal("You must specify an environment name") exit 1 end env = Chef::Environment.new env.name(env_name) env.description(config[:description]) if config[:description] create_object(env) end end end end chef-11.8.2/lib/chef/knife/cookbook_site_show.rb0000644000004100000410000000351212254362222021527 0ustar www-datawww-data# Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class CookbookSiteShow < Knife banner "knife cookbook site show COOKBOOK [VERSION] (options)" category "cookbook site" def run output(format_for_display(get_cookbook_data)) end def get_cookbook_data case @name_args.length when 1 noauth_rest.get_rest("http://cookbooks.opscode.com/api/v1/cookbooks/#{@name_args[0]}") when 2 noauth_rest.get_rest("http://cookbooks.opscode.com/api/v1/cookbooks/#{@name_args[0]}/versions/#{name_args[1].gsub('.', '_')}") end end def get_cookbook_list(items=10, start=0, cookbook_collection={}) cookbooks_url = "http://cookbooks.opscode.com/api/v1/cookbooks?items=#{items}&start=#{start}" cr = noauth_rest.get_rest(cookbooks_url) cr["items"].each do |cookbook| cookbook_collection[cookbook["cookbook_name"]] = cookbook end new_start = start + cr["items"].length if new_start < cr["total"] get_cookbook_list(items, new_start, cookbook_collection) else cookbook_collection end end end end end chef-11.8.2/lib/chef/knife/cookbook_metadata_from_file.rb0000644000004100000410000000232312254362222023324 0ustar www-datawww-data# # # Author:: Adam Jacob () # Author:: Matthew Kent () # Copyright:: Copyright (c) 2009 Opscode, Inc. # Copyright:: Copyright (c) 2010 Matthew Kent # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class CookbookMetadataFromFile < Knife deps do require 'chef/cookbook/metadata' end banner "knife cookbook metadata from FILE (options)" def run file = @name_args[0] cookbook = File.basename(File.dirname(file)) @metadata = Chef::Knife::CookbookMetadata.new @metadata.generate_metadata_from_file(cookbook, file) end end end end chef-11.8.2/lib/chef/knife/cookbook_metadata.rb0000644000004100000410000000707712254362222021315 0ustar www-datawww-data# # # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class CookbookMetadata < Knife deps do require 'chef/cookbook_loader' require 'chef/cookbook/metadata' end banner "knife cookbook metadata COOKBOOK (options)" option :cookbook_path, :short => "-o PATH:PATH", :long => "--cookbook-path PATH:PATH", :description => "A colon-separated path to look for cookbooks in", :proc => lambda { |o| o.split(":") } option :all, :short => "-a", :long => "--all", :description => "Generate metadata for all cookbooks, rather than just a single cookbook" def run config[:cookbook_path] ||= Chef::Config[:cookbook_path] if config[:all] cl = Chef::CookbookLoader.new(config[:cookbook_path]) cl.load_cookbooks cl.each do |cname, cookbook| generate_metadata(cname.to_s) end else cookbook_name = @name_args[0] if cookbook_name.nil? || cookbook_name.empty? ui.error "You must specify the cookbook to generate metadata for, or use the --all option." exit 1 end generate_metadata(cookbook_name) end end def generate_metadata(cookbook) Array(config[:cookbook_path]).reverse.each do |path| file = File.expand_path(File.join(path, cookbook, 'metadata.rb')) if File.exists?(file) generate_metadata_from_file(cookbook, file) else validate_metadata_json(path, cookbook) end end end def generate_metadata_from_file(cookbook, file) ui.info("Generating metadata for #{cookbook} from #{file}") md = Chef::Cookbook::Metadata.new md.name(cookbook) md.from_file(file) json_file = File.join(File.dirname(file), 'metadata.json') File.open(json_file, "w") do |f| f.write(Chef::JSONCompat.to_json_pretty(md)) end generated = true Chef::Log.debug("Generated #{json_file}") rescue Exceptions::ObsoleteDependencySyntax, Exceptions::InvalidVersionConstraint => e ui.stderr.puts "ERROR: The cookbook '#{cookbook}' contains invalid or obsolete metadata syntax." ui.stderr.puts "in #{file}:" ui.stderr.puts ui.stderr.puts e.message exit 1 end def validate_metadata_json(path, cookbook) json_file = File.join(path, cookbook, 'metadata.json') if File.exist?(json_file) Chef::Cookbook::Metadata.validate_json(IO.read(json_file)) end rescue Exceptions::ObsoleteDependencySyntax, Exceptions::InvalidVersionConstraint => e ui.stderr.puts "ERROR: The cookbook '#{cookbook}' contains invalid or obsolete metadata syntax." ui.stderr.puts "in #{json_file}:" ui.stderr.puts ui.stderr.puts e.message exit 1 end end end end chef-11.8.2/lib/chef/knife/node_run_list_remove.rb0000644000004100000410000000226512254362222022062 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class NodeRunListRemove < Knife deps do require 'chef/node' require 'chef/json_compat' end banner "knife node run_list remove [NODE] [ENTRIES] (options)" def run node = Chef::Node.load(@name_args[0]) entries = @name_args[1].split(',') entries.each { |e| node.run_list.remove(e) } node.save config[:run_list] = true output(format_for_display(node)) end end end end chef-11.8.2/lib/chef/knife/data_bag_delete.rb0000644000004100000410000000264512254362222020707 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class DataBagDelete < Knife deps do require 'chef/data_bag' end banner "knife data bag delete BAG [ITEM] (options)" category "data bag" def run if @name_args.length == 2 delete_object(Chef::DataBagItem, @name_args[1], "data_bag_item") do rest.delete_rest("data/#{@name_args[0]}/#{@name_args[1]}") end elsif @name_args.length == 1 delete_object(Chef::DataBag, @name_args[0], "data_bag") do rest.delete_rest("data/#{@name_args[0]}") end else show_usage ui.fatal("You must specify at least a data bag name") exit 1 end end end end end chef-11.8.2/lib/chef/knife/tag_list.rb0000644000004100000410000000227112254362222017444 0ustar www-datawww-data# # Author:: Ryan Davis () # Author:: Daniel DeLeo () # Author:: Nuo Yan () # Copyright:: Copyright (c) 2011 Ryan Davis and Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/knife' class Chef class Knife class TagList < Knife deps do require 'chef/node' end banner "knife tag list NODE" def run name = @name_args[0] if name.nil? show_usage ui.fatal("You must specify a node name.") exit 1 end node = Chef::Node.load(name) output(node.tags) end end end end chef-11.8.2/lib/chef/streaming_cookbook_uploader.rb0000644000004100000410000001637212254362222022323 0ustar www-datawww-data# inspired by/cargo-culted from http://stanislavvitvitskiy.blogspot.com/2008/12/multipart-post-in-ruby.html # On Apr 6, 2010, at 3:00 PM, Stanislav Vitvitskiy wrote: # # It's free to use / modify / distribute. No need to mention anything. Just copy/paste and use. # # Regards, # Stan require 'net/http' require 'mixlib/authentication/signedheaderauth' require 'openssl' require 'chef/version' class Chef class StreamingCookbookUploader DefaultHeaders = { 'accept' => 'application/json', 'x-chef-version' => ::Chef::VERSION } class << self def post(to_url, user_id, secret_key_filename, params = {}, headers = {}) make_request(:post, to_url, user_id, secret_key_filename, params, headers) end def put(to_url, user_id, secret_key_filename, params = {}, headers = {}) make_request(:put, to_url, user_id, secret_key_filename, params, headers) end def make_request(http_verb, to_url, user_id, secret_key_filename, params = {}, headers = {}) Chef::Log.warn('[DEPRECATED] StreamingCookbookUploader class is deprecated. It will be removed in Chef 12. Please use CookbookSiteStreamingUploader instead.') boundary = '----RubyMultipartClient' + rand(1000000).to_s + 'ZZZZZ' parts = [] content_file = nil timestamp = Time.now.utc.iso8601 secret_key = OpenSSL::PKey::RSA.new(File.read(secret_key_filename)) unless params.nil? || params.empty? params.each do |key, value| if value.kind_of?(File) content_file = value filepath = value.path filename = File.basename(filepath) parts << StringPart.new( "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"" + key.to_s + "\"; filename=\"" + filename + "\"\r\n" + "Content-Type: application/octet-stream\r\n\r\n") parts << StreamPart.new(value, File.size(filepath)) parts << StringPart.new("\r\n") else parts << StringPart.new( "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"" + key.to_s + "\"\r\n\r\n") parts << StringPart.new(value.to_s + "\r\n") end end parts << StringPart.new("--" + boundary + "--\r\n") end body_stream = MultipartStream.new(parts) timestamp = Time.now.utc.iso8601 url = URI.parse(to_url) Chef::Log.logger.debug("Signing: method: #{http_verb}, path: #{url.path}, file: #{content_file}, User-id: #{user_id}, Timestamp: #{timestamp}") # We use the body for signing the request if the file parameter # wasn't a valid file or wasn't included. Extract the body (with # multi-part delimiters intact) to sign the request. # TODO: tim: 2009-12-28: It'd be nice to remove this special case, and # always hash the entire request body. In the file case it would just be # expanded multipart text - the entire body of the POST. content_body = parts.inject("") { |result,part| result + part.read(0, part.size) } content_file.rewind if content_file # we consumed the file for the above operation, so rewind it. signing_options = { :http_method=>http_verb, :path=>url.path, :user_id=>user_id, :timestamp=>timestamp} (content_file && signing_options[:file] = content_file) || (signing_options[:body] = (content_body || "")) headers.merge!(Mixlib::Authentication::SignedHeaderAuth.signing_object(signing_options).sign(secret_key)) content_file.rewind if content_file # net/http doesn't like symbols for header keys, so we'll to_s each one just in case headers = DefaultHeaders.merge(Hash[*headers.map{ |k,v| [k.to_s, v] }.flatten]) req = case http_verb when :put Net::HTTP::Put.new(url.path, headers) when :post Net::HTTP::Post.new(url.path, headers) end req.content_length = body_stream.size req.content_type = 'multipart/form-data; boundary=' + boundary unless parts.empty? req.body_stream = body_stream http = Net::HTTP.new(url.host, url.port) if url.scheme == "https" http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE end res = http.request(req) #res = http.start {|http_proc| http_proc.request(req) } # alias status to code and to_s to body for test purposes # TODO: stop the following madness! class << res alias :to_s :body # BUGBUG this makes the response compatible with what respsonse_steps expects to test headers (response.headers[] -> response[]) def headers self end def status code.to_i end end res end end class StreamPart def initialize(stream, size) Chef::Log.warn('[DEPRECATED] StreamingCookbookUploader::StreamPart class is deprecated. It will be removed in Chef 12. Please use CookbookSiteStreamingUploader::StreamPart instead.') @stream, @size = stream, size end def size @size end # read the specified amount from the stream def read(offset, how_much) @stream.read(how_much) end end class StringPart def initialize(str) Chef::Log.warn('[DEPRECATED] StreamingCookbookUploader::StringPart class is deprecated. It will be removed in Chef 12. Please use CookbookSiteStreamingUploader::StringPart instead.') @str = str end def size @str.length end # read the specified amount from the string startiung at the offset def read(offset, how_much) @str[offset, how_much] end end class MultipartStream def initialize(parts) Chef::Log.warn('[DEPRECATED] StreamingCookbookUploader::MultipartStream class is deprecated. It will be removed in Chef 12. Please use CookbookSiteStreamingUploader::MultipartStream instead.') @parts = parts @part_no = 0 @part_offset = 0 end def size @parts.inject(0) {|size, part| size + part.size} end def read(how_much) return nil if @part_no >= @parts.size how_much_current_part = @parts[@part_no].size - @part_offset how_much_current_part = if how_much_current_part > how_much how_much else how_much_current_part end how_much_next_part = how_much - how_much_current_part current_part = @parts[@part_no].read(@part_offset, how_much_current_part) # recurse into the next part if the current one was not large enough if how_much_next_part > 0 @part_no += 1 @part_offset = 0 next_part = read(how_much_next_part) current_part + if next_part next_part else '' end else @part_offset += how_much_current_part current_part end end end end end chef-11.8.2/lib/chef/shef/0000755000004100000410000000000012254362222015140 5ustar www-datawww-datachef-11.8.2/lib/chef/shef/ext.rb0000644000004100000410000000131412254362222016264 0ustar www-datawww-data#-- # Author:: Joshua Timberman () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/shell/ext' chef-11.8.2/lib/chef/rest.rb0000644000004100000410000001407612254362222015525 0ustar www-datawww-data#-- # Author:: Adam Jacob () # Author:: Thom May () # Author:: Nuo Yan () # Author:: Christopher Brown () # Author:: Christopher Walters () # Copyright:: Copyright (c) 2009, 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'tempfile' require 'chef/http' class Chef class HTTP; end class REST < HTTP; end end require 'chef/http/authenticator' require 'chef/http/decompressor' require 'chef/http/json_input' require 'chef/http/json_to_model_output' require 'chef/http/cookie_manager' require 'chef/config' require 'chef/exceptions' require 'chef/platform/query_helpers' class Chef # == Chef::REST # Chef's custom REST client with built-in JSON support and RSA signed header # authentication. class REST < HTTP # Backwards compatibility for things that use # Chef::REST::RESTRequest or its constants RESTRequest = HTTP::HTTPRequest attr_accessor :url, :cookies, :sign_on_redirect, :redirect_limit attr_reader :authenticator # Create a REST client object. The supplied +url+ is used as the base for # all subsequent requests. For example, when initialized with a base url # http://localhost:4000, a call to +get_rest+ with 'nodes' will make an # HTTP GET request to http://localhost:4000/nodes def initialize(url, client_name=Chef::Config[:node_name], signing_key_filename=Chef::Config[:client_key], options={}) options[:client_name] = client_name options[:signing_key_filename] = signing_key_filename super(url, options) @decompressor = Decompressor.new(options) @authenticator = Authenticator.new(options) @middlewares << JSONInput.new(options) @middlewares << JSONToModelOutput.new(options) @middlewares << CookieManager.new(options) @middlewares << @decompressor @middlewares << @authenticator end def signing_key_filename authenticator.signing_key_filename end def auth_credentials authenticator.auth_credentials end def client_name authenticator.client_name end def signing_key authenticator.raw_key end def sign_requests? authenticator.sign_requests? end # Send an HTTP GET request to the path # # Using this method to +fetch+ a file is considered deprecated. # # === Parameters # path:: The path to GET # raw:: Whether you want the raw body returned, or JSON inflated. Defaults # to JSON inflated. def get(path, raw=false, headers={}) if raw streaming_request(path, headers) else request(:GET, path, headers) end end alias :get_rest :get alias :delete_rest :delete alias :post_rest :post alias :put_rest :put # Streams a download to a tempfile, then yields the tempfile to a block. # After the download, the tempfile will be closed and unlinked. # If you rename the tempfile, it will not be deleted. # Beware that if the server streams infinite content, this method will # stream it until you run out of disk space. def fetch(path, headers={}) streaming_request(create_url(path), headers) {|tmp_file| yield tmp_file } end alias :api_request :request # Do a HTTP request where no middleware is loaded (e.g. JSON input/output # conversion) but the standard Chef Authentication headers are added to the # request. def raw_http_request(method, path, headers, data) url = create_url(path) method, url, headers, data = @authenticator.handle_request(method, url, headers, data) response, rest_request, return_value = send_http_request(method, url, headers, data) response.error! unless success_response?(response) return_value rescue Exception => exception log_failed_request(response, return_value) unless response.nil? if exception.respond_to?(:chef_rest_request=) exception.chef_rest_request = rest_request end raise end # Deprecated: # Responsibilities of this method have been split up. The #http_client is # now responsible for making individual requests, while # #retrying_http_errors handles error/retry logic. def retriable_http_request(method, url, req_body, headers) rest_request = Chef::HTTP::HTTPRequest.new(method, url, req_body, headers) Chef::Log.debug("Sending HTTP Request via #{method} to #{url.host}:#{url.port}#{rest_request.path}") retrying_http_errors(url) do yield rest_request end end # Customized streaming behavior; sets the accepted content type to "*/*" # if not otherwise specified for compatibility purposes def streaming_request(url, headers, &block) headers["Accept"] ||= "*/*" super end alias :retriable_rest_request :retriable_http_request def follow_redirect unless @sign_on_redirect @authenticator.sign_request = false end super ensure @authenticator.sign_request = true end public :create_url def http_client(base_url=nil) base_url ||= url BasicClient.new(base_url, :ssl_policy => Chef::HTTP::APISSLPolicy) end ############################################################################ # DEPRECATED ############################################################################ def decompress_body(body) @decompressor.decompress_body(body) end def authentication_headers(method, url, json_body=nil) authenticator.authentication_headers(method, url, json_body) end end end chef-11.8.2/lib/chef/http.rb0000644000004100000410000003050212254362222015517 0ustar www-datawww-data#-- # Author:: Adam Jacob () # Author:: Thom May () # Author:: Nuo Yan () # Author:: Christopher Brown () # Author:: Christopher Walters () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009, 2010, 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'net/https' require 'uri' require 'chef/http/basic_client' require 'chef/monkey_patches/string' require 'chef/monkey_patches/net_http' require 'chef/config' require 'chef/exceptions' class Chef # == Chef::HTTP # Basic HTTP client, with support for adding features via middleware class HTTP # Class for applying middleware behaviors to streaming # responses. Collects stream handlers (if any) from each # middleware. When #handle_chunk is called, the chunk gets # passed to all handlers in turn for processing. class StreamHandler def initialize(middlewares, response) middlewares = middlewares.flatten @stream_handlers = [] middlewares.each do |middleware| stream_handler = middleware.stream_response_handler(response) @stream_handlers << stream_handler unless stream_handler.nil? end end def handle_chunk(next_chunk) @stream_handlers.inject(next_chunk) do |chunk, handler| handler.handle_chunk(chunk) end end end def self.middlewares @middlewares ||= [] end def self.use(middleware_class) middlewares << middleware_class end attr_reader :url attr_reader :sign_on_redirect attr_reader :redirect_limit attr_reader :middlewares # Create a HTTP client object. The supplied +url+ is used as the base for # all subsequent requests. For example, when initialized with a base url # http://localhost:4000, a call to +get+ with 'nodes' will make an # HTTP GET request to http://localhost:4000/nodes def initialize(url, options={}) @url = url @default_headers = options[:headers] || {} @sign_on_redirect = true @redirects_followed = 0 @redirect_limit = 10 @middlewares = [] self.class.middlewares.each do |middleware_class| @middlewares << middleware_class.new(options) end end # Send an HTTP HEAD request to the path # # === Parameters # path:: path part of the request URL def head(path, headers={}) request(:HEAD, path, headers) end # Send an HTTP GET request to the path # # === Parameters # path:: The path to GET def get(path, headers={}) request(:GET, path, headers) end # Send an HTTP PUT request to the path # # === Parameters # path:: path part of the request URL def put(path, json, headers={}) request(:PUT, path, headers, json) end # Send an HTTP POST request to the path # # === Parameters # path:: path part of the request URL def post(path, json, headers={}) request(:POST, path, headers, json) end # Send an HTTP DELETE request to the path # # === Parameters # path:: path part of the request URL def delete(path, headers={}) request(:DELETE, path, headers) end # Makes an HTTP request to +path+ with the given +method+, +headers+, and # +data+ (if applicable). def request(method, path, headers={}, data=false) url = create_url(path) method, url, headers, data = apply_request_middleware(method, url, headers, data) response, rest_request, return_value = send_http_request(method, url, headers, data) response, rest_request, return_value = apply_response_middleware(response, rest_request, return_value) response.error! unless success_response?(response) return_value rescue Exception => exception log_failed_request(response, return_value) unless response.nil? if exception.respond_to?(:chef_rest_request=) exception.chef_rest_request = rest_request end raise end # Makes a streaming download request, streaming the response body to a # tempfile. If a block is given, the tempfile is passed to the block and # the tempfile will automatically be unlinked after the block is executed. # # If no block is given, the tempfile is returned, which means it's up to # you to unlink the tempfile when you're done with it. def streaming_request(path, headers={}, &block) url = create_url(path) response, rest_request, return_value = nil, nil, nil tempfile = nil method = :GET method, url, headers, data = apply_request_middleware(method, url, headers, data) response, rest_request, return_value = send_http_request(method, url, headers, data) do |http_response| if http_response.kind_of?(Net::HTTPSuccess) tempfile = stream_to_tempfile(url, http_response) if block_given? begin yield tempfile ensure tempfile && tempfile.close! end end end end unless response.kind_of?(Net::HTTPSuccess) or response.kind_of?(Net::HTTPRedirection) response.error! end tempfile rescue Exception => e log_failed_request(response, return_value) unless response.nil? if e.respond_to?(:chef_rest_request=) e.chef_rest_request = rest_request end raise end def http_client(base_url=nil) base_url ||= url BasicClient.new(base_url) end protected def create_url(path) return path if path.is_a?(URI) if path =~ /^(http|https):\/\// URI.parse(path) elsif path.nil? or path.empty? URI.parse(@url) else URI.parse("#{@url}/#{path}") end end def apply_request_middleware(method, url, headers, data) middlewares.inject([method, url, headers, data]) do |req_data, middleware| middleware.handle_request(*req_data) end end def apply_response_middleware(response, rest_request, return_value) middlewares.reverse.inject([response, rest_request, return_value]) do |res_data, middleware| middleware.handle_response(*res_data) end end def log_failed_request(response, return_value) return_value ||= {} error_message = "HTTP Request Returned #{response.code} #{response.message}: " error_message << (return_value["error"].respond_to?(:join) ? return_value["error"].join(", ") : return_value["error"].to_s) Chef::Log.info(error_message) end def success_response?(response) response.kind_of?(Net::HTTPSuccess) || response.kind_of?(Net::HTTPRedirection) end # Runs a synchronous HTTP request, with no middleware applied (use #request # to have the middleware applied). The entire response will be loaded into memory. def send_http_request(method, url, headers, body, &response_handler) headers = build_headers(method, url, headers, body) retrying_http_errors(url) do client = http_client(url) return_value = nil if block_given? request, response = client.request(method, url, body, headers, &response_handler) else request, response = client.request(method, url, body, headers) {|r| r.read_body } return_value = response.read_body end @last_response = response Chef::Log.debug("---- HTTP Status and Header Data: ----") Chef::Log.debug("HTTP #{response.http_version} #{response.code} #{response.msg}") response.each do |header, value| Chef::Log.debug("#{header}: #{value}") end Chef::Log.debug("---- End HTTP Status/Header Data ----") if response.kind_of?(Net::HTTPSuccess) [response, request, return_value] elsif response.kind_of?(Net::HTTPNotModified) # Must be tested before Net::HTTPRedirection because it's subclass. [response, request, false] elsif redirect_location = redirected_to(response) if [:GET, :HEAD].include?(method) follow_redirect do send_http_request(method, create_url(redirect_location), headers, body, &response_handler) end else raise Exceptions::InvalidRedirect, "#{method} request was redirected from #{url} to #{redirect_location}. Only GET and HEAD support redirects." end else [response, request, nil] end end end # Wraps an HTTP request with retry logic. # === Arguments # url:: URL of the request, used for error messages def retrying_http_errors(url) http_attempts = 0 begin http_attempts += 1 yield rescue SocketError, Errno::ETIMEDOUT => e e.message.replace "Error connecting to #{url} - #{e.message}" raise e rescue Errno::ECONNREFUSED if http_retry_count - http_attempts + 1 > 0 Chef::Log.error("Connection refused connecting to #{url}, retry #{http_attempts}/#{http_retry_count}") sleep(http_retry_delay) retry end raise Errno::ECONNREFUSED, "Connection refused connecting to #{url}, giving up" rescue Timeout::Error if http_retry_count - http_attempts + 1 > 0 Chef::Log.error("Timeout connecting to #{url}, retry #{http_attempts}/#{http_retry_count}") sleep(http_retry_delay) retry end raise Timeout::Error, "Timeout connecting to #{url}, giving up" rescue Net::HTTPFatalError => e if http_retry_count - http_attempts + 1 > 0 sleep_time = 1 + (2 ** http_attempts) + rand(2 ** http_attempts) Chef::Log.error("Server returned error for #{url}, retrying #{http_attempts}/#{http_retry_count} in #{sleep_time}s") sleep(sleep_time) retry end raise end end def http_retry_delay config[:http_retry_delay] end def http_retry_count config[:http_retry_count] end def config Chef::Config end def follow_redirect raise Chef::Exceptions::RedirectLimitExceeded if @redirects_followed >= redirect_limit @redirects_followed += 1 Chef::Log.debug("Following redirect #{@redirects_followed}/#{redirect_limit}") yield ensure @redirects_followed = 0 end private def redirected_to(response) return nil unless response.kind_of?(Net::HTTPRedirection) # Net::HTTPNotModified is undesired subclass of Net::HTTPRedirection so test for this return nil if response.kind_of?(Net::HTTPNotModified) response['location'] end def build_headers(method, url, headers={}, json_body=false) headers = @default_headers.merge(headers) headers['Content-Length'] = json_body.bytesize.to_s if json_body headers.merge!(Chef::Config[:custom_http_headers]) if Chef::Config[:custom_http_headers] headers end def stream_to_tempfile(url, response) tf = Tempfile.open("chef-rest") if Chef::Platform.windows? tf.binmode # required for binary files on Windows platforms end Chef::Log.debug("Streaming download from #{url.to_s} to tempfile #{tf.path}") # Stolen from http://www.ruby-forum.com/topic/166423 # Kudos to _why! stream_handler = StreamHandler.new(middlewares, response) response.read_body do |chunk| tf.write(stream_handler.handle_chunk(chunk)) end tf.close tf rescue Exception tf.close! raise end public ############################################################################ # DEPRECATED ############################################################################ # This is only kept around to provide access to cache control data in # lib/chef/provider/remote_file/http.rb # Find a better API. def last_response @last_response end end end chef-11.8.2/lib/chef/config_fetcher.rb0000644000004100000410000000430612254362222017510 0ustar www-datawww-datarequire 'chef/application' require 'chef/chef_fs/path_utils' require 'chef/http/simple' require 'chef/json_compat' class Chef class ConfigFetcher attr_reader :config_location attr_reader :config_file_jail def initialize(config_location, config_file_jail=nil) @config_location = config_location @config_file_jail = config_file_jail end def fetch_json config_data = read_config begin Chef::JSONCompat.from_json(config_data) rescue JSON::ParserError => error Chef::Application.fatal!("Could not parse the provided JSON file (#{config_location}): " + error.message, 2) end end def read_config if remote_config? fetch_remote_config else read_local_config end end def fetch_remote_config http.get("") rescue SocketError, SystemCallError, Net::HTTPServerException => error Chef::Application.fatal!("Cannot fetch config '#{config_location}': '#{error.class}: #{error.message}", 2) end def read_local_config ::File.read(config_location) rescue Errno::ENOENT => error Chef::Application.fatal!("Cannot load configuration from #{config_location}", 2) rescue Errno::EACCES => error Chef::Application.fatal!("Permissions are incorrect on #{config_location}. Please chmod a+r #{config_location}", 2) end def config_missing? return false if remote_config? # Check if the config file exists, and check if it is underneath the config file jail begin real_config_file = Pathname.new(config_location).realpath.to_s rescue Errno::ENOENT return true end # If realpath succeeded, the file exists return false if !config_file_jail begin real_jail = Pathname.new(config_file_jail).realpath.to_s rescue Errno::ENOENT Chef::Log.warn("Config file jail #{config_file_jail} does not exist: will not load any config file.") return true end !Chef::ChefFS::PathUtils.descendant_of?(real_config_file, real_jail) end def http Chef::HTTP::Simple.new(config_location) end def remote_config? !!(config_location =~ %r{^(http|https)://}) end end end chef-11.8.2/lib/chef/resources.rb0000644000004100000410000000476612254362222016567 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource/apt_package' require 'chef/resource/bash' require 'chef/resource/batch' require 'chef/resource/breakpoint' require 'chef/resource/cookbook_file' require 'chef/resource/chef_gem' require 'chef/resource/cron' require 'chef/resource/csh' require 'chef/resource/deploy' require 'chef/resource/deploy_revision' require 'chef/resource/directory' require 'chef/resource/dpkg_package' require 'chef/resource/easy_install_package' require 'chef/resource/env' require 'chef/resource/erl_call' require 'chef/resource/execute' require 'chef/resource/file' require 'chef/resource/freebsd_package' require 'chef/resource/ips_package' require 'chef/resource/gem_package' require 'chef/resource/git' require 'chef/resource/group' require 'chef/resource/http_request' require 'chef/resource/ifconfig' require 'chef/resource/link' require 'chef/resource/log' require 'chef/resource/macports_package' require 'chef/resource/mdadm' require 'chef/resource/mount' require 'chef/resource/ohai' require 'chef/resource/package' require 'chef/resource/pacman_package' require 'chef/resource/perl' require 'chef/resource/portage_package' require 'chef/resource/powershell_script' require 'chef/resource/python' require 'chef/resource/registry_key' require 'chef/resource/remote_directory' require 'chef/resource/remote_file' require 'chef/resource/rpm_package' require 'chef/resource/solaris_package' require 'chef/resource/route' require 'chef/resource/ruby' require 'chef/resource/ruby_block' require 'chef/resource/scm' require 'chef/resource/script' require 'chef/resource/service' require 'chef/resource/subversion' require 'chef/resource/smartos_package' require 'chef/resource/template' require 'chef/resource/timestamped_deploy' require 'chef/resource/user' require 'chef/resource/yum_package' require 'chef/resource/lwrp_base' require 'chef/resource/bff_package' chef-11.8.2/lib/chef/knife.rb0000644000004100000410000005133712254362222015645 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Brown () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'forwardable' require 'chef/version' require 'mixlib/cli' require 'chef/config_fetcher' require 'chef/mixin/convert_to_class_name' require 'chef/mixin/path_sanity' require 'chef/knife/core/subcommand_loader' require 'chef/knife/core/ui' require 'chef/rest' require 'pp' class Chef class Knife Chef::REST::RESTRequest.user_agent = "Chef Knife#{Chef::REST::RESTRequest::UA_COMMON}" include Mixlib::CLI include Chef::Mixin::PathSanity extend Chef::Mixin::ConvertToClassName extend Forwardable # Backwards Compat: # Ideally, we should not vomit all of these methods into this base class; # instead, they should be accessed by hitting the ui object directly. def_delegator :@ui, :stdout def_delegator :@ui, :stderr def_delegator :@ui, :stdin def_delegator :@ui, :msg def_delegator :@ui, :ask_question def_delegator :@ui, :pretty_print def_delegator :@ui, :output def_delegator :@ui, :format_list_for_display def_delegator :@ui, :format_for_display def_delegator :@ui, :format_cookbook_list_for_display def_delegator :@ui, :edit_data def_delegator :@ui, :edit_object def_delegator :@ui, :confirm attr_accessor :name_args attr_accessor :ui # Configure mixlib-cli to always separate defaults from user-supplied CLI options def self.use_separate_defaults? true end def self.ui @ui ||= Chef::Knife::UI.new(STDOUT, STDERR, STDIN, {}) end def self.msg(msg="") ui.msg(msg) end def self.reset_subcommands! @@subcommands = {} @subcommands_by_category = nil end def self.inherited(subclass) unless subclass.unnamed? subcommands[subclass.snake_case_name] = subclass end end # Explicitly set the category for the current command to +new_category+ # The category is normally determined from the first word of the command # name, but some commands make more sense using two or more words # ===Arguments # new_category::: A String to set the category to (see examples) # ===Examples: # Data bag commands would be in the 'data' category by default. To put them # in the 'data bag' category: # category('data bag') def self.category(new_category) @category = new_category end def self.subcommand_category @category || snake_case_name.split('_').first unless unnamed? end def self.snake_case_name convert_to_snake_case(name.split('::').last) unless unnamed? end def self.common_name snake_case_name.split('_').join(' ') end # Does this class have a name? (Classes created via Class.new don't) def self.unnamed? name.nil? || name.empty? end def self.subcommand_loader @subcommand_loader ||= Knife::SubcommandLoader.new(chef_config_dir) end def self.load_commands @commands_loaded ||= subcommand_loader.load_commands end def self.subcommands @@subcommands ||= {} end def self.subcommands_by_category unless @subcommands_by_category @subcommands_by_category = Hash.new { |hash, key| hash[key] = [] } subcommands.each do |snake_cased, klass| @subcommands_by_category[klass.subcommand_category] << snake_cased end end @subcommands_by_category end # Print the list of subcommands knife knows about. If +preferred_category+ # is given, only subcommands in that category are shown def self.list_commands(preferred_category=nil) load_commands category_desc = preferred_category ? preferred_category + " " : '' msg "Available #{category_desc}subcommands: (for details, knife SUB-COMMAND --help)\n\n" if preferred_category && subcommands_by_category.key?(preferred_category) commands_to_show = {preferred_category => subcommands_by_category[preferred_category]} else commands_to_show = subcommands_by_category end commands_to_show.sort.each do |category, commands| next if category =~ /deprecated/i msg "** #{category.upcase} COMMANDS **" commands.sort.each do |command| msg subcommands[command].banner if subcommands[command] end msg end end # Run knife for the given +args+ (ARGV), adding +options+ to the list of # CLI options that the subcommand knows how to handle. # ===Arguments # args::: usually ARGV # options::: A Mixlib::CLI option parser hash. These +options+ are how # subcommands know about global knife CLI options def self.run(args, options={}) load_commands subcommand_class = subcommand_class_from(args) subcommand_class.options = options.merge!(subcommand_class.options) subcommand_class.load_deps instance = subcommand_class.new(args) instance.configure_chef instance.run_with_pretty_exceptions end def self.guess_category(args) category_words = args.select {|arg| arg =~ /^(([[:alnum:]])[[:alnum:]\_\-]+)$/ } category_words.map! {|w| w.split('-')}.flatten! matching_category = nil while (!matching_category) && (!category_words.empty?) candidate_category = category_words.join(' ') matching_category = candidate_category if subcommands_by_category.key?(candidate_category) matching_category || category_words.pop end matching_category end def self.subcommand_class_from(args) command_words = args.select {|arg| arg =~ /^(([[:alnum:]])[[:alnum:]\_\-]+)$/ } subcommand_class = nil while ( !subcommand_class ) && ( !command_words.empty? ) snake_case_class_name = command_words.join("_") unless subcommand_class = subcommands[snake_case_class_name] command_words.pop end end # see if we got the command as e.g., knife node-list subcommand_class ||= subcommands[args.first.gsub('-', '_')] subcommand_class || subcommand_not_found!(args) end def self.dependency_loaders @dependency_loaders ||= [] end def self.deps(&block) dependency_loaders << block end def self.load_deps dependency_loaders.each do |dep_loader| dep_loader.call end end private OFFICIAL_PLUGINS = %w[ec2 rackspace windows openstack terremark bluebox] # :nodoc: # Error out and print usage. probably becuase the arguments given by the # user could not be resolved to a subcommand. def self.subcommand_not_found!(args) ui.fatal("Cannot find sub command for: '#{args.join(' ')}'") if category_commands = guess_category(args) list_commands(category_commands) elsif missing_plugin = ( OFFICIAL_PLUGINS.find {|plugin| plugin == args[0]} ) ui.info("The #{missing_plugin} commands were moved to plugins in Chef 0.10") ui.info("You can install the plugin with `(sudo) gem install knife-#{missing_plugin}") else list_commands end exit 10 end def self.working_directory ENV['PWD'] || Dir.pwd end def self.reset_config_path! @@chef_config_dir = nil end reset_config_path! # search upward from current_dir until .chef directory is found def self.chef_config_dir if @@chef_config_dir.nil? # share this with subclasses @@chef_config_dir = false full_path = working_directory.split(File::SEPARATOR) (full_path.length - 1).downto(0) do |i| candidate_directory = File.join(full_path[0..i] + [".chef" ]) if File.exist?(candidate_directory) && File.directory?(candidate_directory) @@chef_config_dir = candidate_directory break end end end @@chef_config_dir end public # Create a new instance of the current class configured for the given # arguments and options def initialize(argv=[]) super() # having to call super in initialize is the most annoying anti-pattern :( @ui = Chef::Knife::UI.new(STDOUT, STDERR, STDIN, config) command_name_words = self.class.snake_case_name.split('_') # Mixlib::CLI ignores the embedded name_args @name_args = parse_options(argv) @name_args.delete(command_name_words.join('-')) @name_args.reject! { |name_arg| command_name_words.delete(name_arg) } # knife node run_list add requires that we have extra logic to handle # the case that command name words could be joined by an underscore :/ command_name_words = command_name_words.join('_') @name_args.reject! { |name_arg| command_name_words == name_arg } if config[:help] msg opt_parser exit 1 end # copy Mixlib::CLI over so that it cab be configured in knife.rb # config file Chef::Config[:verbosity] = config[:verbosity] end def parse_options(args) super rescue OptionParser::InvalidOption => e puts "Error: " + e.to_s show_usage exit(1) end # Returns a subset of the Chef::Config[:knife] Hash that is relevant to the # currently executing knife command. This is used by #configure_chef to # apply settings from knife.rb to the +config+ hash. def config_file_settings config_file_settings = {} self.class.options.keys.each do |key| config_file_settings[key] = Chef::Config[:knife][key] if Chef::Config[:knife].has_key?(key) end config_file_settings end def self.config_fetcher(candidate_config) Chef::ConfigFetcher.new(candidate_config, Chef::Config.config_file_jail) end def self.locate_config_file candidate_configs = [] # Look for $KNIFE_HOME/knife.rb (allow multiple knives config on same machine) if ENV['KNIFE_HOME'] candidate_configs << File.join(ENV['KNIFE_HOME'], 'knife.rb') end # Look for $PWD/knife.rb if Dir.pwd candidate_configs << File.join(Dir.pwd, 'knife.rb') end # Look for $UPWARD/.chef/knife.rb if chef_config_dir candidate_configs << File.join(chef_config_dir, 'knife.rb') end # Look for $HOME/.chef/knife.rb if ENV['HOME'] candidate_configs << File.join(ENV['HOME'], '.chef', 'knife.rb') end candidate_configs.each do | candidate_config | fetcher = config_fetcher(candidate_config) if !fetcher.config_missing? return candidate_config end end return nil end # Apply Config in this order: # defaults from mixlib-cli # settings from config file, via Chef::Config[:knife] # config from command line def merge_configs # Apply config file settings on top of mixlib-cli defaults combined_config = default_config.merge(config_file_settings) # Apply user-supplied options on top of the above combination combined_config = combined_config.merge(config) # replace the config hash from mixlib-cli with our own. # Need to use the mutate-in-place #replace method instead of assigning to # the instance variable because other code may have a reference to the # original config hash object. config.replace(combined_config) end # Catch-all method that does any massaging needed for various config # components, such as expanding file paths and converting verbosity level # into log level. def apply_computed_config Chef::Config[:color] = config[:color] case Chef::Config[:verbosity] when 0, nil Chef::Config[:log_level] = :error when 1 Chef::Config[:log_level] = :info else Chef::Config[:log_level] = :debug end Chef::Config[:node_name] = config[:node_name] if config[:node_name] Chef::Config[:client_key] = config[:client_key] if config[:client_key] Chef::Config[:chef_server_url] = config[:chef_server_url] if config[:chef_server_url] Chef::Config[:environment] = config[:environment] if config[:environment] Chef::Config.local_mode = config[:local_mode] if config.has_key?(:local_mode) if Chef::Config.local_mode && !Chef::Config.has_key?(:cookbook_path) && !Chef::Config.has_key?(:chef_repo_path) Chef::Config.chef_repo_path = Chef::Config.find_chef_repo_path(Dir.pwd) end Chef::Config.chef_zero.port = config[:chef_zero_port] if config[:chef_zero_port] # Expand a relative path from the config directory. Config from command # line should already be expanded, and absolute paths will be unchanged. if Chef::Config[:client_key] && config[:config_file] Chef::Config[:client_key] = File.expand_path(Chef::Config[:client_key], File.dirname(config[:config_file])) end Mixlib::Log::Formatter.show_time = false Chef::Log.init(Chef::Config[:log_location]) Chef::Log.level(Chef::Config[:log_level] || :error) if Chef::Config[:node_name] && Chef::Config[:node_name].bytesize > 90 # node names > 90 bytes only work with authentication protocol >= 1.1 # see discussion in config.rb. Chef::Config[:authentication_protocol_version] = "1.1" end end def configure_chef if !config[:config_file] located_config_file = self.class.locate_config_file config[:config_file] = located_config_file if located_config_file end # Don't try to load a knife.rb if it wasn't specified. if config[:config_file] fetcher = Chef::ConfigFetcher.new(config[:config_file], Chef::Config.config_file_jail) if fetcher.config_missing? ui.error("Specified config file #{config[:config_file]} does not exist#{Chef::Config.config_file_jail ? " or is not under config file jail #{Chef::Config.config_file_jail}" : ""}!") exit 1 end Chef::Log.debug("Using configuration from #{config[:config_file]}") read_config(fetcher.read_config, config[:config_file]) else # ...but do log a message if no config was found. Chef::Config[:color] = config[:color] ui.warn("No knife configuration file found") end merge_configs apply_computed_config end def read_config(config_content, config_file_path) Chef::Config.from_string(config_content, config_file_path) rescue SyntaxError => e ui.error "You have invalid ruby syntax in your config file #{config_file_path}" ui.info(ui.color(e.message, :red)) if file_line = e.message[/#{Regexp.escape(config_file_path)}:[\d]+/] line = file_line[/:([\d]+)$/, 1].to_i highlight_config_error(config_file_path, line) end exit 1 rescue Exception => e ui.error "You have an error in your config file #{config_file_path}" ui.info "#{e.class.name}: #{e.message}" filtered_trace = e.backtrace.grep(/#{Regexp.escape(config_file_path)}/) filtered_trace.each {|line| ui.msg(" " + ui.color(line, :red))} if !filtered_trace.empty? line_nr = filtered_trace.first[/#{Regexp.escape(config_file_path)}:([\d]+)/, 1] highlight_config_error(config_file_path, line_nr.to_i) end exit 1 end def highlight_config_error(file, line) config_file_lines = [] IO.readlines(file).each_with_index {|l, i| config_file_lines << "#{(i + 1).to_s.rjust(3)}: #{l.chomp}"} if line == 1 lines = config_file_lines[0..3] lines[0] = ui.color(lines[0], :red) else lines = config_file_lines[Range.new(line - 2, line)] lines[1] = ui.color(lines[1], :red) end ui.msg "" ui.msg ui.color(" # #{file}", :white) lines.each {|l| ui.msg(l)} ui.msg "" end def show_usage stdout.puts("USAGE: " + self.opt_parser.to_s) end def run_with_pretty_exceptions(raise_exception = false) unless self.respond_to?(:run) ui.error "You need to add a #run method to your knife command before you can use it" end enforce_path_sanity Chef::Application.setup_server_connectivity begin run ensure Chef::Application.destroy_server_connectivity end rescue Exception => e raise if raise_exception || Chef::Config[:verbosity] == 2 humanize_exception(e) exit 100 end def humanize_exception(e) case e when SystemExit raise # make sure exit passes through. when Net::HTTPServerException, Net::HTTPFatalError humanize_http_exception(e) when Errno::ECONNREFUSED, Timeout::Error, Errno::ETIMEDOUT, SocketError ui.error "Network Error: #{e.message}" ui.info "Check your knife configuration and network settings" when NameError, NoMethodError ui.error "knife encountered an unexpected error" ui.info "This may be a bug in the '#{self.class.common_name}' knife command or plugin" ui.info "Please collect the output of this command with the `-VV` option before filing a bug report." ui.info "Exception: #{e.class.name}: #{e.message}" when Chef::Exceptions::PrivateKeyMissing ui.error "Your private key could not be loaded from #{api_key}" ui.info "Check your configuration file and ensure that your private key is readable" when Chef::Exceptions::InvalidRedirect ui.error "Invalid Redirect: #{e.message}" ui.info "Change your server location in knife.rb to the server's FQDN to avoid unwanted redirections." else ui.error "#{e.class.name}: #{e.message}" end end def humanize_http_exception(e) response = e.response case response when Net::HTTPUnauthorized ui.error "Failed to authenticate to #{server_url} as #{username} with key #{api_key}" ui.info "Response: #{format_rest_error(response)}" when Net::HTTPForbidden ui.error "You authenticated successfully to #{server_url} as #{username} but you are not authorized for this action" ui.info "Response: #{format_rest_error(response)}" when Net::HTTPBadRequest ui.error "The data in your request was invalid" ui.info "Response: #{format_rest_error(response)}" when Net::HTTPNotFound ui.error "The object you are looking for could not be found" ui.info "Response: #{format_rest_error(response)}" when Net::HTTPInternalServerError ui.error "internal server error" ui.info "Response: #{format_rest_error(response)}" when Net::HTTPBadGateway ui.error "bad gateway" ui.info "Response: #{format_rest_error(response)}" when Net::HTTPServiceUnavailable ui.error "Service temporarily unavailable" ui.info "Response: #{format_rest_error(response)}" else ui.error response.message ui.info "Response: #{format_rest_error(response)}" end end def username Chef::Config[:node_name] end def api_key Chef::Config[:client_key] end # Parses JSON from the error response sent by Chef Server and returns the # error message #-- # TODO: this code belongs in Chef::REST def format_rest_error(response) Array(Chef::JSONCompat.from_json(response.body)["error"]).join('; ') rescue Exception response.body end def create_object(object, pretty_name=nil, &block) output = edit_data(object) if Kernel.block_given? output = block.call(output) else output.save end pretty_name ||= output self.msg("Created #{pretty_name}") output(output) if config[:print_after] end def delete_object(klass, name, delete_name=nil, &block) confirm("Do you really want to delete #{name}") if Kernel.block_given? object = block.call else object = klass.load(name) object.destroy end output(format_for_display(object)) if config[:print_after] obj_name = delete_name ? "#{delete_name}[#{name}]" : object self.msg("Deleted #{obj_name}") end def rest @rest ||= begin require 'chef/rest' Chef::REST.new(Chef::Config[:chef_server_url]) end end def noauth_rest @rest ||= begin require 'chef/rest' Chef::REST.new(Chef::Config[:chef_server_url], false, false) end end def server_url Chef::Config[:chef_server_url] end end end chef-11.8.2/lib/chef/dsl/0000755000004100000410000000000012254362222014775 5ustar www-datawww-datachef-11.8.2/lib/chef/dsl/data_query.rb0000644000004100000410000000411312254362222017457 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/search/query' require 'chef/data_bag' require 'chef/data_bag_item' require 'chef/encrypted_data_bag_item' class Chef module DSL # ==Chef::DSL::DataQuery # Provides DSL for querying data from the chef-server via search or data # bag. module DataQuery def search(*args, &block) # If you pass a block, or have at least the start argument, do raw result parsing # # Otherwise, do the iteration for the end user if Kernel.block_given? || args.length >= 4 Chef::Search::Query.new.search(*args, &block) else results = Array.new Chef::Search::Query.new.search(*args) do |o| results << o end results end end def data_bag(bag) DataBag.validate_name!(bag.to_s) rbag = DataBag.load(bag) rbag.keys rescue Exception Log.error("Failed to list data bag items in data bag: #{bag.inspect}") raise end def data_bag_item(bag, item) DataBag.validate_name!(bag.to_s) DataBagItem.validate_id!(item) DataBagItem.load(bag, item) rescue Exception Log.error("Failed to load data bag item: #{bag.inspect} #{item.inspect}") raise end end end end # **DEPRECATED** # This used to be part of chef/mixin/language. Load the file to activate the deprecation code. require 'chef/mixin/language' chef-11.8.2/lib/chef/dsl/include_attribute.rb0000644000004100000410000000431212254362222021030 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008, 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/log' class Chef module DSL module IncludeAttribute # Loads the attribute file specified by the short name of the # file, e.g., loads specified cookbook's # "attributes/mailservers.rb" # if passed # "mailservers" def include_attribute(*attr_file_specs) attr_file_specs.flatten.each do |attr_file_spec| cookbook_name, attr_file = parse_attribute_file_spec(attr_file_spec) if run_context.loaded_fully_qualified_attribute?(cookbook_name, attr_file) Chef::Log.debug("I am not loading attribute file #{cookbook_name}::#{attr_file}, because I have already seen it.") else Chef::Log.debug("Loading Attribute #{cookbook_name}::#{attr_file}") run_context.loaded_attribute(cookbook_name, attr_file) attr_file_path = run_context.resolve_attribute(cookbook_name, attr_file) node.from_file(attr_file_path) end end true end # Takes a attribute file specification, like "apache2" or "mysql::server" # and converts it to a 2 element array of [cookbook_name, attribute_file_name] def parse_attribute_file_spec(file_spec) if match = file_spec.match(/(.+?)::(.+)/) [match[1], match[2]] else [file_spec, "default"] end end end end end # **DEPRECATED** # This used to be part of chef/mixin/language_include_attribute. Load the file to activate the deprecation code. require 'chef/mixin/language_include_attribute' chef-11.8.2/lib/chef/dsl/platform_introspection.rb0000644000004100000410000001723112254362222022132 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef module DSL # == Chef::DSL::PlatformIntrospection # Provides the DSL for platform-dependent switch logic, such as # #value_for_platform. module PlatformIntrospection # Implementation class for determining platform dependent values class PlatformDependentValue # Create a platform dependent value object. # === Arguments # platform_hash (Hash) a hash of the same structure as Chef::Platform, # like this: # { # :debian => {:default => 'the value for all debian'} # [:centos, :redhat, :fedora] => {:default => "value for all EL variants"} # :ubuntu => { :default => "default for ubuntu", '10.04' => "value for 10.04 only"}, # :default => "the default when nothing else matches" # } # * platforms can be specified as Symbols or Strings # * multiple platforms can be grouped by using an Array as the key # * values for platforms need to be Hashes of the form: # {platform_version => value_for_that_version} # * the exception to the above is the default value, which is given as # :default => default_value def initialize(platform_hash) @values = {} platform_hash.each { |platforms, value| set(platforms, value)} end def value_for_node(node) platform, version = node[:platform].to_s, node[:platform_version].to_s if @values.key?(platform) && @values[platform].key?(version) @values[platform][version] elsif @values.key?(platform) && @values[platform].key?("default") @values[platform]["default"] elsif @values.key?("default") @values["default"] else nil end end private def set(platforms, value) if platforms.to_s == 'default' @values["default"] = value else assert_valid_platform_values!(platforms, value) Array(platforms).each { |platform| @values[platform.to_s] = normalize_keys(value)} value end end def normalize_keys(hash) hash.inject({}) do |h, key_value| keys, value = *key_value Array(keys).each do |key| h[key.to_s] = value end h end end def assert_valid_platform_values!(platforms, value) unless value.kind_of?(Hash) msg = "platform dependent values must be specified in the format :platform => {:version => value} " msg << "you gave a value #{value.inspect} for platform(s) #{platforms}" raise ArgumentError, msg end end end # Given a hash similar to the one we use for Platforms, select a value from the hash. Supports # per platform defaults, along with a single base default. Arrays may be passed as hash keys and # will be expanded. # # === Parameters # platform_hash:: A platform-style hash. # # === Returns # value:: Whatever the most specific value of the hash is. def value_for_platform(platform_hash) PlatformDependentValue.new(platform_hash).value_for_node(node) end # Given a list of platforms, returns true if the current recipe is being run on a node with # that platform, false otherwise. # # === Parameters # args:: A list of platforms. Each platform can be in string or symbol format. # # === Returns # true:: If the current platform is in the list # false:: If the current platform is not in the list def platform?(*args) has_platform = false args.flatten.each do |platform| has_platform = true if platform.to_s == node[:platform] end has_platform end # Implementation class for determining platform family dependent values class PlatformFamilyDependentValue # Create a platform family dependent value object. # === Arguments # platform_family_hash (Hash) a map of platform families to values. # like this: # { # :rhel => "value for all EL variants" # :fedora => "value for fedora variants fedora and amazon" , # [:fedora, :rhel] => "value for all known redhat variants" # :debian => "value for debian variants including debian, ubuntu, mint" , # :default => "the default when nothing else matches" # } # * platform families can be specified as Symbols or Strings # * multiple platform families can be grouped by using an Array as the key # * values for platform families can be any object, with no restrictions. Some examples: # - [:stop, :start] # - "mysql-devel" # - { :key => "value" } def initialize(platform_family_hash) @values = {} @values["default"] = nil platform_family_hash.each { |platform_families, value| set(platform_families, value)} end def value_for_node(node) if node.key?(:platform_family) platform_family = node[:platform_family].to_s if @values.key?(platform_family) @values[platform_family] else @values["default"] end else @values["default"] end end private def set(platform_family, value) if platform_family.to_s == 'default' @values["default"] = value else Array(platform_family).each { |family| @values[family.to_s] = value } value end end end # Given a hash mapping platform families to values, select a value from the hash. Supports a single # base default if platform family is not in the map. Arrays may be passed as hash keys and will be # expanded # # === Parameters # platform_family_hash:: A hash in the form { platform_family_name => value } # # === Returns # value:: Whatever the most specific value of the hash is. def value_for_platform_family(platform_family_hash) PlatformFamilyDependentValue.new(platform_family_hash).value_for_node(node) end # Given a list of platform families, returns true if the current recipe is being run on a # node within that platform family, false otherwise. # # === Parameters # args:: A list of platform families. Each platform family can be in string or symbol format. # # === Returns # true:: if the current node platform family is in the list. # false:: if the current node platform family is not in the list. def platform_family?(*args) args.flatten.any? do |platform_family| platform_family.to_s == node[:platform_family] end end end end end # **DEPRECATED** # This used to be part of chef/mixin/language. Load the file to activate the deprecation code. require 'chef/mixin/language' chef-11.8.2/lib/chef/dsl/recipe.rb0000644000004100000410000000663012254362222016576 0ustar www-datawww-data#-- # Author:: Adam Jacob () # Author:: Christopher Walters () # Copyright:: Copyright (c) 2008, 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/resource' require 'chef/resource_platform_map' require 'chef/mixin/convert_to_class_name' class Chef module DSL # == Chef::DSL::Recipe # Provides the primary recipe DSL functionality for defining Chef resource # objects via method calls. module Recipe include Chef::Mixin::ConvertToClassName def method_missing(method_symbol, *args, &block) # If we have a definition that matches, we want to use that instead. This should # let you do some really crazy over-riding of "native" types, if you really want # to. if run_context.definitions.has_key?(method_symbol) # This dupes the high level object, but we still need to dup the params new_def = run_context.definitions[method_symbol].dup new_def.params = new_def.params.dup new_def.node = run_context.node # This sets up the parameter overrides new_def.instance_eval(&block) if block new_recipe = Chef::Recipe.new(cookbook_name, @recipe_name, run_context) new_recipe.params = new_def.params new_recipe.params[:name] = args[0] new_recipe.instance_eval(&new_def.recipe) else # Otherwise, we're rocking the regular resource call route. # Checks the new platform => short_name => resource mapping initially # then fall back to the older approach (Chef::Resource.const_get) for # backward compatibility resource_class = Chef::Resource.resource_for_node(method_symbol, run_context.node) super unless resource_class raise ArgumentError, "You must supply a name when declaring a #{method_symbol} resource" unless args.size > 0 # If we have a resource like this one, we want to steal its state args << run_context resource = resource_class.new(*args) resource.source_line = caller[0] resource.load_prior_resource resource.cookbook_name = cookbook_name resource.recipe_name = @recipe_name resource.params = @params # Determine whether this resource is being created in the context of an enclosing Provider resource.enclosing_provider = self.is_a?(Chef::Provider) ? self : nil # Evaluate resource attribute DSL resource.instance_eval(&block) if block # Run optional resource hook resource.after_created run_context.resource_collection.insert(resource) resource end end end end end # **DEPRECATED** # This used to be part of chef/mixin/recipe_definition_dsl_core. Load the file to activate the deprecation code. require 'chef/mixin/recipe_definition_dsl_core' chef-11.8.2/lib/chef/dsl/registry_helper.rb0000644000004100000410000000456012254362222020536 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # # # Helper functions to access the windows registry from within recipes and # the not_if/only_if blocks in resources. This only exposes the methods # in the chef/win32/registry class which are reasonably side-effect-free. # The actual modification of the registry should be done via the registry_key # resource in a more idempotent way. # # class Chef module DSL module RegistryHelper # the registry instance is cheap to build and throwing it away ensures we # don't carry any state (e.g. magic 32-bit/64-bit settings) between calls def registry_key_exists?(key_path, architecture = :machine) registry = Chef::Win32::Registry.new(run_context, architecture) registry.key_exists?(key_path) end def registry_get_values(key_path, architecture = :machine) registry = Chef::Win32::Registry.new(run_context, architecture) registry.get_values(key_path) end def registry_has_subkeys?(key_path, architecture = :machine) registry = Chef::Win32::Registry.new(run_context, architecture) registry.has_subkeys?(key_path) end def registry_get_subkeys(key_path, architecture = :machine) registry = Chef::Win32::Registry.new(run_context, architecture) registry.get_subkeys(key_path) end def registry_value_exists?(key_path, value, architecture = :machine) registry = Chef::Win32::Registry.new(run_context, architecture) registry.value_exists?(key_path, value) end def registry_data_exists?(key_path, value, architecture = :machine) registry = Chef::Win32::Registry.new(run_context, architecture) registry.data_exists?(key_path, value) end end end end chef-11.8.2/lib/chef/dsl/include_recipe.rb0000644000004100000410000000247012254362222020277 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008, 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/log' class Chef module DSL module IncludeRecipe def include_recipe(*recipe_names) run_context.include_recipe(*recipe_names) end def load_recipe(recipe_name) run_context.load_recipe(recipe_name) end def require_recipe(*args) Chef::Log.warn("require_recipe is deprecated and will be removed in a future release, please use include_recipe") include_recipe(*args) end end end end # **DEPRECATED** # This used to be part of chef/mixin/language_include_recipe. Load the file to activate the deprecation code. require 'chef/mixin/language_include_recipe' chef-11.8.2/lib/chef/platform.rb0000644000004100000410000000162712254362222016372 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/platform/provider_mapping' require 'chef/platform/query_helpers' class Chef class Platform # Functionality for this class is defined in chef/platform/provider_mapping # and chef/platform/query_helpers end end chef-11.8.2/lib/chef/platform/0000755000004100000410000000000012254362222016037 5ustar www-datawww-datachef-11.8.2/lib/chef/platform/provider_mapping.rb0000644000004100000410000004713612254362222021744 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/config' require 'chef/log' require 'chef/mixin/params_validate' require 'chef/version_constraint/platform' # This file depends on nearly every provider in chef, but requiring them # directly causes circular requires resulting in uninitialized constant errors. require 'chef/provider' require 'chef/provider/log' require 'chef/provider/user' require 'chef/provider/group' require 'chef/provider/mount' require 'chef/provider/service' require 'chef/provider/package' require 'chef/provider/ifconfig' class Chef class Platform class << self attr_writer :platforms def platforms @platforms ||= { :mac_os_x => { :default => { :package => Chef::Provider::Package::Macports, :service => Chef::Provider::Service::Macosx, :user => Chef::Provider::User::Dscl, :group => Chef::Provider::Group::Dscl } }, :mac_os_x_server => { :default => { :package => Chef::Provider::Package::Macports, :service => Chef::Provider::Service::Macosx, :user => Chef::Provider::User::Dscl, :group => Chef::Provider::Group::Dscl } }, :freebsd => { :default => { :group => Chef::Provider::Group::Pw, :package => Chef::Provider::Package::Freebsd, :service => Chef::Provider::Service::Freebsd, :user => Chef::Provider::User::Pw, :cron => Chef::Provider::Cron } }, :ubuntu => { :default => { :package => Chef::Provider::Package::Apt, :service => Chef::Provider::Service::Debian, :cron => Chef::Provider::Cron, :mdadm => Chef::Provider::Mdadm }, ">= 11.10" => { :ifconfig => Chef::Provider::Ifconfig::Debian } }, :gcel => { :default => { :package => Chef::Provider::Package::Apt, :service => Chef::Provider::Service::Debian, :cron => Chef::Provider::Cron, :mdadm => Chef::Provider::Mdadm } }, :linaro => { :default => { :package => Chef::Provider::Package::Apt, :service => Chef::Provider::Service::Debian, :cron => Chef::Provider::Cron, :mdadm => Chef::Provider::Mdadm } }, :raspbian => { :default => { :package => Chef::Provider::Package::Apt, :service => Chef::Provider::Service::Debian, :cron => Chef::Provider::Cron, :mdadm => Chef::Provider::Mdadm } }, :linuxmint => { :default => { :package => Chef::Provider::Package::Apt, :service => Chef::Provider::Service::Upstart, :cron => Chef::Provider::Cron, :mdadm => Chef::Provider::Mdadm } }, :debian => { :default => { :package => Chef::Provider::Package::Apt, :service => Chef::Provider::Service::Debian, :cron => Chef::Provider::Cron, :mdadm => Chef::Provider::Mdadm }, ">= 6.0" => { :service => Chef::Provider::Service::Insserv }, ">= 7.0" => { :ifconfig => Chef::Provider::Ifconfig::Debian } }, :xenserver => { :default => { :service => Chef::Provider::Service::Redhat, :cron => Chef::Provider::Cron, :package => Chef::Provider::Package::Yum, :mdadm => Chef::Provider::Mdadm } }, :xcp => { :default => { :service => Chef::Provider::Service::Redhat, :cron => Chef::Provider::Cron, :package => Chef::Provider::Package::Yum, :mdadm => Chef::Provider::Mdadm } }, :centos => { :default => { :service => Chef::Provider::Service::Redhat, :cron => Chef::Provider::Cron, :package => Chef::Provider::Package::Yum, :mdadm => Chef::Provider::Mdadm, :ifconfig => Chef::Provider::Ifconfig::Redhat } }, :amazon => { :default => { :service => Chef::Provider::Service::Redhat, :cron => Chef::Provider::Cron, :package => Chef::Provider::Package::Yum, :mdadm => Chef::Provider::Mdadm } }, :scientific => { :default => { :service => Chef::Provider::Service::Redhat, :cron => Chef::Provider::Cron, :package => Chef::Provider::Package::Yum, :mdadm => Chef::Provider::Mdadm } }, :fedora => { :default => { :service => Chef::Provider::Service::Redhat, :cron => Chef::Provider::Cron, :package => Chef::Provider::Package::Yum, :mdadm => Chef::Provider::Mdadm, :ifconfig => Chef::Provider::Ifconfig::Redhat } }, :opensuse => { :default => { :service => Chef::Provider::Service::Redhat, :cron => Chef::Provider::Cron, :package => Chef::Provider::Package::Zypper, :group => Chef::Provider::Group::Suse }, ">= 12.3" => { :group => Chef::Provider::Group::Usermod } }, :suse => { :default => { :service => Chef::Provider::Service::Redhat, :cron => Chef::Provider::Cron, :package => Chef::Provider::Package::Zypper, :group => Chef::Provider::Group::Suse }, ############################################### # TODO: Remove this after ohai update is released. # Only OpenSuSE 12.3+ should use the Usermod group provider: # Ohai before OHAI-339 is applied reports both OpenSuSE and SuSE # Enterprise as "suse", Ohai after OHAI-339 will report OpenSuSE as # "opensuse". # # In order to support OpenSuSE both before and after the Ohai # change, I'm leaving this here. It needs to get removed before # SuSE enterprise 12.3 ships. ">= 12.3" => { :group => Chef::Provider::Group::Usermod } }, :oracle => { :default => { :service => Chef::Provider::Service::Redhat, :cron => Chef::Provider::Cron, :package => Chef::Provider::Package::Yum, :mdadm => Chef::Provider::Mdadm } }, :redhat => { :default => { :service => Chef::Provider::Service::Redhat, :cron => Chef::Provider::Cron, :package => Chef::Provider::Package::Yum, :mdadm => Chef::Provider::Mdadm, :ifconfig => Chef::Provider::Ifconfig::Redhat } }, :gentoo => { :default => { :package => Chef::Provider::Package::Portage, :service => Chef::Provider::Service::Gentoo, :cron => Chef::Provider::Cron, :mdadm => Chef::Provider::Mdadm } }, :arch => { :default => { :package => Chef::Provider::Package::Pacman, :service => Chef::Provider::Service::Arch, :cron => Chef::Provider::Cron, :mdadm => Chef::Provider::Mdadm } }, :mswin => { :default => { :env => Chef::Provider::Env::Windows, :service => Chef::Provider::Service::Windows, :user => Chef::Provider::User::Windows, :group => Chef::Provider::Group::Windows, :mount => Chef::Provider::Mount::Windows } }, :mingw32 => { :default => { :env => Chef::Provider::Env::Windows, :service => Chef::Provider::Service::Windows, :user => Chef::Provider::User::Windows, :group => Chef::Provider::Group::Windows, :mount => Chef::Provider::Mount::Windows } }, :windows => { :default => { :env => Chef::Provider::Env::Windows, :service => Chef::Provider::Service::Windows, :user => Chef::Provider::User::Windows, :group => Chef::Provider::Group::Windows, :mount => Chef::Provider::Mount::Windows } }, :solaris => {}, :openindiana => { :default => { :service => Chef::Provider::Service::Solaris, :package => Chef::Provider::Package::Ips, :cron => Chef::Provider::Cron::Solaris, :group => Chef::Provider::Group::Usermod } }, :opensolaris => { :default => { :service => Chef::Provider::Service::Solaris, :package => Chef::Provider::Package::Ips, :cron => Chef::Provider::Cron::Solaris, :group => Chef::Provider::Group::Usermod } }, :nexentacore => { :default => { :service => Chef::Provider::Service::Solaris, :package => Chef::Provider::Package::Solaris, :cron => Chef::Provider::Cron::Solaris, :group => Chef::Provider::Group::Usermod } }, :omnios => { :default => { :service => Chef::Provider::Service::Solaris, :package => Chef::Provider::Package::Ips, :cron => Chef::Provider::Cron::Solaris, :group => Chef::Provider::Group::Usermod, :user => Chef::Provider::User::Solaris, } }, :solaris2 => { :default => { :service => Chef::Provider::Service::Solaris, :package => Chef::Provider::Package::Ips, :cron => Chef::Provider::Cron::Solaris, :group => Chef::Provider::Group::Usermod, :user => Chef::Provider::User::Solaris, }, ">= 5.9" => { :service => Chef::Provider::Service::Solaris, :package => Chef::Provider::Package::Solaris, :cron => Chef::Provider::Cron::Solaris, :group => Chef::Provider::Group::Usermod, :user => Chef::Provider::User::Solaris, } }, :smartos => { :default => { :service => Chef::Provider::Service::Solaris, :package => Chef::Provider::Package::SmartOS, :cron => Chef::Provider::Cron::Solaris, :group => Chef::Provider::Group::Usermod } }, :netbsd => { :default => { :service => Chef::Provider::Service::Freebsd, :group => Chef::Provider::Group::Groupmod } }, :openbsd => { :default => { :group => Chef::Provider::Group::Usermod } }, :hpux => { :default => { :group => Chef::Provider::Group::Usermod } }, :aix => { :default => { :group => Chef::Provider::Group::Aix, :mount => Chef::Provider::Mount::Aix, :ifconfig => Chef::Provider::Ifconfig::Aix, :cron => Chef::Provider::Cron::Aix, :package => Chef::Provider::Package::Aix } }, :default => { :file => Chef::Provider::File, :directory => Chef::Provider::Directory, :link => Chef::Provider::Link, :template => Chef::Provider::Template, :remote_directory => Chef::Provider::RemoteDirectory, :execute => Chef::Provider::Execute, :mount => Chef::Provider::Mount::Mount, :script => Chef::Provider::Script, :service => Chef::Provider::Service::Init, :perl => Chef::Provider::Script, :python => Chef::Provider::Script, :ruby => Chef::Provider::Script, :bash => Chef::Provider::Script, :csh => Chef::Provider::Script, :user => Chef::Provider::User::Useradd, :group => Chef::Provider::Group::Gpasswd, :http_request => Chef::Provider::HttpRequest, :route => Chef::Provider::Route, :ifconfig => Chef::Provider::Ifconfig, :ruby_block => Chef::Provider::RubyBlock, :erl_call => Chef::Provider::ErlCall, :log => Chef::Provider::Log::ChefLog } } end include Chef::Mixin::ParamsValidate def find(name, version) provider_map = platforms[:default].clone name_sym = name if name.kind_of?(String) name.downcase! name.gsub!(/\s/, "_") name_sym = name.to_sym end if platforms.has_key?(name_sym) platform_versions = platforms[name_sym].select {|k, v| k != :default } if platforms[name_sym].has_key?(:default) provider_map.merge!(platforms[name_sym][:default]) end platform_versions.each do |platform_version, provider| begin version_constraint = Chef::VersionConstraint::Platform.new(platform_version) if version_constraint.include?(version) Chef::Log.debug("Platform #{name.to_s} version #{version} found") provider_map.merge!(provider) end rescue Chef::Exceptions::InvalidPlatformVersion Chef::Log.debug("Chef::Version::Comparable does not know how to parse the platform version: #{version}") end end else Chef::Log.debug("Platform #{name} not found, using all defaults. (Unsupported platform?)") end provider_map end def find_platform_and_version(node) platform = nil version = nil if node[:platform] platform = node[:platform] elsif node.attribute?("os") platform = node[:os] end raise ArgumentError, "Cannot find a platform for #{node}" unless platform if node[:platform_version] version = node[:platform_version] elsif node[:os_version] version = node[:os_version] elsif node[:os_release] version = node[:os_release] end raise ArgumentError, "Cannot find a version for #{node}" unless version return platform, version end def provider_for_resource(resource, action=:nothing) node = resource.run_context && resource.run_context.node raise ArgumentError, "Cannot find the provider for a resource with no run context set" unless node provider = find_provider_for_node(node, resource).new(resource, resource.run_context) provider.action = action provider end def provider_for_node(node, resource_type) raise NotImplementedError, "#{self.class.name} no longer supports #provider_for_node" find_provider_for_node(node, resource_type).new(node, resource_type) end def find_provider_for_node(node, resource_type) platform, version = find_platform_and_version(node) find_provider(platform, version, resource_type) end def set(args) validate( args, { :platform => { :kind_of => Symbol, :required => false, }, :version => { :kind_of => String, :required => false, }, :resource => { :kind_of => Symbol, }, :provider => { :kind_of => [ String, Symbol, Class ], } } ) if args.has_key?(:platform) if args.has_key?(:version) if platforms.has_key?(args[:platform]) if platforms[args[:platform]].has_key?(args[:version]) platforms[args[:platform]][args[:version]][args[:resource].to_sym] = args[:provider] else platforms[args[:platform]][args[:version]] = { args[:resource].to_sym => args[:provider] } end else platforms[args[:platform]] = { args[:version] => { args[:resource].to_sym => args[:provider] } } end else if platforms.has_key?(args[:platform]) if platforms[args[:platform]].has_key?(:default) platforms[args[:platform]][:default][args[:resource].to_sym] = args[:provider] else platforms[args[:platform]] = { :default => { args[:resource].to_sym => args[:provider] } } end else platforms[args[:platform]] = { :default => { args[:resource].to_sym => args[:provider] } } end end else if platforms.has_key?(:default) platforms[:default][args[:resource].to_sym] = args[:provider] else platforms[:default] = { args[:resource].to_sym => args[:provider] } end end end def find_provider(platform, version, resource_type) provider_klass = explicit_provider(platform, version, resource_type) || platform_provider(platform, version, resource_type) || resource_matching_provider(platform, version, resource_type) raise ArgumentError, "Cannot find a provider for #{resource_type} on #{platform} version #{version}" if provider_klass.nil? provider_klass end private def explicit_provider(platform, version, resource_type) resource_type.kind_of?(Chef::Resource) ? resource_type.provider : nil end def platform_provider(platform, version, resource_type) pmap = Chef::Platform.find(platform, version) rtkey = resource_type.kind_of?(Chef::Resource) ? resource_type.resource_name.to_sym : resource_type pmap.has_key?(rtkey) ? pmap[rtkey] : nil end def resource_matching_provider(platform, version, resource_type) if resource_type.kind_of?(Chef::Resource) begin Chef::Provider.const_get(resource_type.class.to_s.split('::').last) rescue NameError nil end else nil end end end end end chef-11.8.2/lib/chef/platform/query_helpers.rb0000644000004100000410000000211712254362222021254 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Platform class << self def windows? if RUBY_PLATFORM =~ /mswin|mingw|windows/ true else false end end def windows_server_2003? return false unless windows? require 'ruby-wmi' host = WMI::Win32_OperatingSystem.find(:first) (host.version && host.version.start_with?("5.2")) end end end end chef-11.8.2/lib/chef/json_compat.rb0000644000004100000410000001221312254362222017053 0ustar www-datawww-data# # Author:: Tim Hinderliter () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # Wrapper class for interacting with JSON. require 'json' require 'yajl' class Chef class JSONCompat JSON_MAX_NESTING = 1000 JSON_CLASS = "json_class".freeze CHEF_APICLIENT = "Chef::ApiClient".freeze CHEF_CHECKSUM = "Chef::Checksum".freeze CHEF_COOKBOOKVERSION = "Chef::CookbookVersion".freeze CHEF_DATABAG = "Chef::DataBag".freeze CHEF_DATABAGITEM = "Chef::DataBagItem".freeze CHEF_ENVIRONMENT = "Chef::Environment".freeze CHEF_NODE = "Chef::Node".freeze CHEF_ROLE = "Chef::Role".freeze CHEF_SANDBOX = "Chef::Sandbox".freeze CHEF_RESOURCE = "Chef::Resource".freeze CHEF_RESOURCECOLLECTION = "Chef::ResourceCollection".freeze class < false # is required to turn it off. if opts[:create_additions].nil? || opts[:create_additions] map_to_rb_obj(obj) else obj end end # Look at an object that's a basic type (from json parse) and convert it # to an instance of Chef classes if desired. def map_to_rb_obj(json_obj) case json_obj when Hash mapped_hash = map_hash_to_rb_obj(json_obj) if json_obj.has_key?(JSON_CLASS) && (class_to_inflate = class_for_json_class(json_obj[JSON_CLASS])) class_to_inflate.json_create(mapped_hash) else mapped_hash end when Array json_obj.map {|e| map_to_rb_obj(e) } else json_obj end end def map_hash_to_rb_obj(json_hash) json_hash.each do |key, value| json_hash[key] = map_to_rb_obj(value) end json_hash end def to_json(obj, opts = nil) obj.to_json(opts_add_max_nesting(opts)) end def to_json_pretty(obj, opts = nil) ::JSON.pretty_generate(obj, opts_add_max_nesting(opts)) end # Map +json_class+ to a Class object. We use a +case+ instead of a Hash # assigned to a constant because otherwise this file could not be loaded # until all the constants were defined, which means you'd have to load # the world to get json, which would make knife very slow. def class_for_json_class(json_class) case json_class when CHEF_APICLIENT Chef::ApiClient when CHEF_CHECKSUM Chef::Checksum when CHEF_COOKBOOKVERSION Chef::CookbookVersion when CHEF_DATABAG Chef::DataBag when CHEF_DATABAGITEM Chef::DataBagItem when CHEF_ENVIRONMENT Chef::Environment when CHEF_NODE Chef::Node when CHEF_ROLE Chef::Role when CHEF_SANDBOX # a falsey return here will disable object inflation/"create # additions" in the caller. In Chef 11 this is correct, we just have # a dummy Chef::Sandbox class for compat with Chef 10 servers. false when CHEF_RESOURCE Chef::Resource when CHEF_RESOURCECOLLECTION Chef::ResourceCollection when /^Chef::Resource/ Chef::Resource.find_subclass_by_name(json_class) else raise JSON::ParserError, "Unsupported `json_class` type '#{json_class}'" end end end end end chef-11.8.2/lib/chef/resource_definition_list.rb0000644000004100000410000000215112254362222021631 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/mixin/from_file' require 'chef/resource_definition' class Chef class ResourceDefinitionList include Chef::Mixin::FromFile attr_accessor :defines def initialize @defines = Hash.new end def define(resource_name, prototype_params=nil, &block) @defines[resource_name] = ResourceDefinition.new @defines[resource_name].define(resource_name, prototype_params, &block) true end end end chef-11.8.2/lib/chef/tasks/0000755000004100000410000000000012254362222015340 5ustar www-datawww-datachef-11.8.2/lib/chef/tasks/chef_repo.rake0000644000004100000410000002504712254362222020146 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008, 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'rubygems' require 'chef/json_compat' require 'chef' require 'chef/role' require 'chef/cookbook/metadata' require 'tempfile' require 'rake' # Allow REMOTE options to be overridden on the command line REMOTE_HOST = ENV["REMOTE_HOST"] if ENV["REMOTE_HOST"] != nil REMOTE_SUDO = ENV["REMOTE_SUDO"] if ENV["REMOTE_SUDO"] != nil if defined? REMOTE_HOST REMOTE_PATH_PREFIX = "#{REMOTE_HOST}:" REMOTE_EXEC_PREFIX = "ssh #{REMOTE_HOST}" REMOTE_EXEC_PREFIX += " sudo" if defined? REMOTE_SUDO LOCAL_EXEC_PREFIX = "" else REMOTE_PATH_PREFIX = "" REMOTE_EXEC_PREFIX = "" LOCAL_EXEC_PREFIX = "sudo" end desc "Update your repository from source control" task :update do puts "** Updating your repository" case $vcs when :svn sh %{svn up} when :git pull = false IO.foreach(File.join(TOPDIR, ".git", "config")) do |line| pull = true if line =~ /\[remote "origin"\]/ end if pull sh %{git pull} else puts "* Skipping git pull, no origin specified" end else puts "* No SCM configured, skipping update" end end desc "Install the latest copy of the repository on this Chef Server" task :install => [ :update, :roles, :upload_cookbooks ] do if File.exists?(File.join(TOPDIR, "config", "server.rb")) puts "* Installing new Chef Server Config" sh "#{LOCAL_EXEC_PREFIX} rsync -rlt --delete --exclude '.svn' --exclude '.git*' config/server.rb #{REMOTE_PATH_PREFIX}#{CHEF_SERVER_CONFIG}" end if File.exists?(File.join(TOPDIR, "config", "client.rb")) puts "* Installing new Chef Client Config" sh "#{LOCAL_EXEC_PREFIX} rsync -rlt --delete --exclude '.svn' --exclude '.git*' config/client.rb #{REMOTE_PATH_PREFIX}#{CHEF_CLIENT_CONFIG}" end end desc "By default, run rake test_cookbooks" task :default => [ :test_cookbooks ] desc "Create a new cookbook (with COOKBOOK=name, optional CB_PREFIX=site-)" task :new_cookbook do puts "***WARN: rake new_cookbook is deprecated. Please use 'knife cookbook create COOKBOOK' command.***" create_cookbook(File.join(TOPDIR, "#{ENV["CB_PREFIX"]}cookbooks")) create_readme(File.join(TOPDIR, "#{ENV["CB_PREFIX"]}cookbooks")) create_metadata(File.join(TOPDIR, "#{ENV["CB_PREFIX"]}cookbooks")) end def create_cookbook(dir) raise "Must provide a COOKBOOK=" unless ENV["COOKBOOK"] puts "** Creating cookbook #{ENV["COOKBOOK"]}" sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "attributes")}" sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "recipes")}" sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "definitions")}" sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "libraries")}" sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "resources")}" sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "providers")}" sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "files", "default")}" sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "templates", "default")}" unless File.exists?(File.join(dir, ENV["COOKBOOK"], "recipes", "default.rb")) open(File.join(dir, ENV["COOKBOOK"], "recipes", "default.rb"), "w") do |file| file.puts <<-EOH # # Cookbook Name:: #{ENV["COOKBOOK"]} # Recipe:: default # # Copyright #{Time.now.year}, #{COMPANY_NAME} # EOH case NEW_COOKBOOK_LICENSE when :apachev2 file.puts <<-EOH # 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. # EOH when :none file.puts <<-EOH # All rights reserved - Do Not Redistribute # EOH end end end end def create_readme(dir) raise "Must provide a COOKBOOK=" unless ENV["COOKBOOK"] puts "** Creating README for cookbook: #{ENV["COOKBOOK"]}" unless File.exists?(File.join(dir, ENV["COOKBOOK"], "README.rdoc")) open(File.join(dir, ENV["COOKBOOK"], "README.md"), "w") do |file| file.puts <<-EOH Description =========== Requirements ============ Attributes ========== Usage ===== EOH end end end def create_metadata(dir) raise "Must provide a COOKBOOK=" unless ENV["COOKBOOK"] puts "** Creating metadata for cookbook: #{ENV["COOKBOOK"]}" case NEW_COOKBOOK_LICENSE when :apachev2 license = "Apache 2.0" when :none license = "All rights reserved" end unless File.exists?(File.join(dir, ENV["COOKBOOK"], "metadata.rb")) open(File.join(dir, ENV["COOKBOOK"], "metadata.rb"), "w") do |file| if File.exists?(File.join(dir, ENV["COOKBOOK"], 'README.rdoc')) long_description = "long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc'))" end file.puts <<-EOH maintainer "#{COMPANY_NAME}" maintainer_email "#{SSL_EMAIL_ADDRESS}" license "#{license}" description "Installs/Configures #{ENV["COOKBOOK"]}" #{long_description} version "0.1" EOH end end end desc "Create a new self-signed SSL certificate for FQDN=foo.example.com" task :ssl_cert do $expect_verbose = true fqdn = ENV["FQDN"] fqdn =~ /^(.+?)\.(.+)$/ hostname = $1 domain = $2 raise "Must provide FQDN!" unless fqdn && hostname && domain keyfile = fqdn.gsub("*", "wildcard") puts "** Creating self signed SSL Certificate for #{fqdn}" sh("(cd #{CADIR} && openssl genrsa 2048 > #{keyfile}.key)") sh("(cd #{CADIR} && chmod 644 #{keyfile}.key)") puts "* Generating Self Signed Certificate Request" tf = Tempfile.new("#{keyfile}.ssl-conf") ssl_config = < #{keyfile}.crt)") sh("(cd #{CADIR} && openssl x509 -noout -fingerprint -text < #{keyfile}.crt > #{keyfile}.info)") sh("(cd #{CADIR} && cat #{keyfile}.crt #{keyfile}.key > #{keyfile}.pem)") sh("(cd #{CADIR} && chmod 644 #{keyfile}.pem)") end rule(%r{\b(?:site-)?cookbooks/[^/]+/metadata\.json\Z} => [ proc { |task_name| task_name.sub(/\.[^.]+$/, '.rb') } ]) do |t| system("knife cookbook metadata from file #{t.source}") end desc "Build cookbook metadata.json from metadata.rb" task :metadata => FileList[File.join(TOPDIR, '*cookbooks', ENV['COOKBOOK'] || '*', 'metadata.rb')].pathmap('%X.json') rule(%r{\broles/\S+\.json\Z} => [ proc { |task_name| task_name.sub(/\.[^.]+$/, '.rb') } ]) do |t| system("knife role from file #{t.source}") end desc "Update roles" task :roles => FileList[File.join(TOPDIR, 'roles', '**', '*.rb')].pathmap('%X.json') desc "Update a specific role" task :role, :role_name do |t, args| system("knife role from file #{File.join(TOPDIR, 'roles', args.role_name)}.rb") end desc "Upload all cookbooks" task :upload_cookbooks => [ :metadata ] task :upload_cookbooks do system("knife cookbook upload --all") end desc "Upload a single cookbook" task :upload_cookbook => [ :metadata ] task :upload_cookbook, :cookbook do |t, args| system("knife cookbook upload #{args.cookbook}") end desc "Test all cookbooks" task :test_cookbooks do system("knife cookbook test --all") end desc "Test a single cookbook" task :test_cookbook, :cookbook do |t, args| system("knife cookbook test #{args.cookbook}") end namespace :databag do path = "data_bags" desc "Upload a single databag" task :upload, :databag do |t, args| input_databag = args[:databag] || 'none_specified' databag = File.join(path, input_databag) if File.exists?(databag) && File.directory?(databag) system "knife data bag create #{input_databag}" Dir.foreach(databag) do |item| name, type = item.split('.') if type == 'json' && name.length > 0 system "knife data bag from file #{input_databag} " + File.join(databag, item) end end else puts "ERROR: Could not find the databag in your databag path (" + File.join(path, input_databag) + "), skipping it" end end desc "Upload all databags" task :upload_all do if File.exists?(path) && File.directory?(path) Dir.foreach(path) do |databag| if databag == databag[/^[\-[:alnum:]_]+$/] Rake::Task['databag:upload'].execute( { :databag => databag } ) end end else puts "ERROR: Could not find any databags, skipping it" end end desc "Create a databag" task :create, :databag do |t, args| input_databag = args[:databag] || 'none_specified' FileUtils.mkdir(path) unless File.exists?(path) databag = File.join(path, input_databag) FileUtils.mkdir(databag) unless File.exists?(databag) end desc "Create a databag item stub" task :create_item, :databag, :item do |t, args| input_databag = args[:databag] || 'none_specified' input_item = args[:item] || false databag = File.join(path, input_databag) if File.exists?(databag) && File.directory?(databag) if input_item json_filename = File.join(databag, "#{input_item}.json") if !File.exists?(json_filename) stub = <) # Author:: Christopher Walters () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/mixin/params_validate' require 'chef/dsl/platform_introspection' require 'chef/dsl/data_query' require 'chef/dsl/registry_helper' require 'chef/mixin/convert_to_class_name' require 'chef/resource/conditional' require 'chef/resource/conditional_action_not_nothing' require 'chef/resource_collection' require 'chef/resource_platform_map' require 'chef/node' require 'chef/mixin/deprecation' class Chef class Resource class Notification < Struct.new(:resource, :action, :notifying_resource) def duplicates?(other_notification) unless other_notification.respond_to?(:resource) && other_notification.respond_to?(:action) msg = "only duck-types of Chef::Resource::Notification can be checked for duplication "\ "you gave #{other_notification.inspect}" raise ArgumentError, msg end other_notification.resource == resource && other_notification.action == action end # If resource and/or notifying_resource is not a resource object, this will look them up in the resource collection # and fix the references from strings to actual Resource objects. def resolve_resource_reference(resource_collection) return resource if resource.kind_of?(Chef::Resource) && notifying_resource.kind_of?(Chef::Resource) if not(resource.kind_of?(Chef::Resource)) fix_resource_reference(resource_collection) end if not(notifying_resource.kind_of?(Chef::Resource)) fix_notifier_reference(resource_collection) end end # This will look up the resource if it is not a Resource Object. It will complain if it finds multiple # resources, can't find a resource, or gets invalid syntax. def fix_resource_reference(resource_collection) matching_resource = resource_collection.find(resource) if Array(matching_resource).size > 1 msg = "Notification #{self} from #{notifying_resource} was created with a reference to multiple resources, "\ "but can only notify one resource. Notifying resource was defined on #{notifying_resource.source_line}" raise Chef::Exceptions::InvalidResourceReference, msg end self.resource = matching_resource rescue Chef::Exceptions::ResourceNotFound => e err = Chef::Exceptions::ResourceNotFound.new(<<-FAIL) resource #{notifying_resource} is configured to notify resource #{resource} with action #{action}, \ but #{resource} cannot be found in the resource collection. #{notifying_resource} is defined in \ #{notifying_resource.source_line} FAIL err.set_backtrace(e.backtrace) raise err rescue Chef::Exceptions::InvalidResourceSpecification => e err = Chef::Exceptions::InvalidResourceSpecification.new(<<-F) Resource #{notifying_resource} is configured to notify resource #{resource} with action #{action}, \ but #{resource.inspect} is not valid syntax to look up a resource in the resource collection. Notification \ is defined near #{notifying_resource.source_line} F err.set_backtrace(e.backtrace) raise err end # This will look up the notifying_resource if it is not a Resource Object. It will complain if it finds multiple # resources, can't find a resource, or gets invalid syntax. def fix_notifier_reference(resource_collection) matching_notifier = resource_collection.find(notifying_resource) if Array(matching_notifier).size > 1 msg = "Notification #{self} from #{notifying_resource} was created with a reference to multiple notifying "\ "resources, but can only originate from one resource. Destination resource was defined "\ "on #{resource.source_line}" raise Chef::Exceptions::InvalidResourceReference, msg end self.notifying_resource = matching_notifier rescue Chef::Exceptions::ResourceNotFound => e err = Chef::Exceptions::ResourceNotFound.new(<<-FAIL) Resource #{resource} is configured to receive notifications from #{notifying_resource} with action #{action}, \ but #{notifying_resource} cannot be found in the resource collection. #{resource} is defined in \ #{resource.source_line} FAIL err.set_backtrace(e.backtrace) raise err rescue Chef::Exceptions::InvalidResourceSpecification => e err = Chef::Exceptions::InvalidResourceSpecification.new(<<-F) Resource #{resource} is configured to receive notifications from #{notifying_resource} with action #{action}, \ but #{notifying_resource.inspect} is not valid syntax to look up a resource in the resource collection. Notification \ is defined near #{resource.source_line} F err.set_backtrace(e.backtrace) raise err end end FORBIDDEN_IVARS = [:@run_context, :@node, :@not_if, :@only_if, :@enclosing_provider] HIDDEN_IVARS = [:@allowed_actions, :@resource_name, :@source_line, :@run_context, :@name, :@node, :@not_if, :@only_if, :@elapsed_time, :@enclosing_provider] include Chef::DSL::DataQuery include Chef::Mixin::ParamsValidate include Chef::DSL::PlatformIntrospection include Chef::DSL::RegistryHelper include Chef::Mixin::ConvertToClassName include Chef::Mixin::Deprecation extend Chef::Mixin::ConvertToClassName if Module.method(:const_defined?).arity == 1 def self.strict_const_defined?(const) const_defined?(const) end else def self.strict_const_defined?(const) const_defined?(const, false) end end # Track all subclasses of Resource. This is used so names can be looked up # when attempting to deserialize from JSON. (See: json_compat) def self.resource_classes # Using a class variable here ensures we have one variable to track # subclasses shared by the entire class hierarchy; without this, each # subclass would have its own list of subclasses. @@resource_classes ||= [] end # Callback when subclass is defined. Adds subclass to list of subclasses. def self.inherited(subclass) resource_classes << subclass end # Look up a subclass by +class_name+ which should be a string that matches # `Subclass.name` def self.find_subclass_by_name(class_name) resource_classes.first {|c| c.name == class_name } end # Set or return the list of "state attributes" implemented by the Resource # subclass. State attributes are attributes that describe the desired state # of the system, such as file permissions or ownership. In general, state # attributes are attributes that could be populated by examining the state # of the system (e.g., File.stat can tell you the permissions on an # existing file). Contrarily, attributes that are not "state attributes" # usually modify the way Chef itself behaves, for example by providing # additional options for a package manager to use when installing a # package. # # This list is used by the Chef client auditing system to extract # information from resources to describe changes made to the system. def self.state_attrs(*attr_names) @state_attrs ||= [] @state_attrs = attr_names unless attr_names.empty? # Return *all* state_attrs that this class has, including inherited ones if superclass.respond_to?(:state_attrs) superclass.state_attrs + @state_attrs else @state_attrs end end # Set or return the "identity attribute" for this resource class. This is # generally going to be the "name attribute" for this resource. In other # words, the resource type plus this attribute uniquely identify a given # bit of state that chef manages. For a File resource, this would be the # path, for a package resource, it will be the package name. This will show # up in chef-client's audit records as a searchable field. def self.identity_attr(attr_name=nil) @identity_attr ||= nil @identity_attr = attr_name if attr_name # If this class doesn't have an identity attr, we'll defer to the superclass: if @identity_attr || !superclass.respond_to?(:identity_attr) @identity_attr else superclass.identity_attr end end def self.dsl_name convert_to_snake_case(name, 'Chef::Resource') end attr_accessor :params attr_accessor :provider attr_accessor :allowed_actions attr_accessor :run_context attr_accessor :cookbook_name attr_accessor :recipe_name attr_accessor :enclosing_provider attr_accessor :source_line attr_accessor :retries attr_accessor :retry_delay attr_reader :updated attr_reader :resource_name attr_reader :not_if_args attr_reader :only_if_args attr_reader :elapsed_time # Each notify entry is a resource/action pair, modeled as an # Struct with a #resource and #action member def initialize(name, run_context=nil) @name = name @run_context = run_context @noop = nil @before = nil @params = Hash.new @provider = nil @allowed_actions = [ :nothing ] @action = :nothing @updated = false @updated_by_last_action = false @supports = {} @ignore_failure = false @retries = 0 @retry_delay = 2 @not_if = [] @only_if = [] @source_line = nil @elapsed_time = 0 @node = run_context ? deprecated_ivar(run_context.node, :node, :warn) : nil end # Returns a Hash of attribute => value for the state attributes declared in # the resource's class definition. def state self.class.state_attrs.inject({}) do |state_attrs, attr_name| state_attrs[attr_name] = send(attr_name) state_attrs end end # Returns the value of the identity attribute, if declared. Falls back to # #name if no identity attribute is declared. def identity if identity_attr = self.class.identity_attr send(identity_attr) else name end end def updated=(true_or_false) Chef::Log.warn("Chef::Resource#updated=(true|false) is deprecated. Please call #updated_by_last_action(true|false) instead.") Chef::Log.warn("Called from:") caller[0..3].each {|line| Chef::Log.warn(line)} updated_by_last_action(true_or_false) @updated = true_or_false end def node run_context && run_context.node end # If an unknown method is invoked, determine whether the enclosing Provider's # lexical scope can fulfill the request. E.g. This happens when the Resource's # block invokes new_resource. def method_missing(method_symbol, *args, &block) if enclosing_provider && enclosing_provider.respond_to?(method_symbol) enclosing_provider.send(method_symbol, *args, &block) else raise NoMethodError, "undefined method `#{method_symbol.to_s}' for #{self.class.to_s}" end end def load_prior_resource begin prior_resource = run_context.resource_collection.lookup(self.to_s) # if we get here, there is a prior resource (otherwise we'd have jumped # to the rescue clause). Chef::Log.warn("Cloning resource attributes for #{self.to_s} from prior resource (CHEF-3694)") Chef::Log.warn("Previous #{prior_resource}: #{prior_resource.source_line}") if prior_resource.source_line Chef::Log.warn("Current #{self}: #{self.source_line}") if self.source_line prior_resource.instance_variables.each do |iv| unless iv.to_sym == :@source_line || iv.to_sym == :@action || iv.to_sym == :@not_if || iv.to_sym == :@only_if self.instance_variable_set(iv, prior_resource.instance_variable_get(iv)) end end true rescue Chef::Exceptions::ResourceNotFound true end end def supports(args={}) if args.any? @supports = args else @supports end end def provider(arg=nil) klass = if arg.kind_of?(String) || arg.kind_of?(Symbol) lookup_provider_constant(arg) else arg end set_or_return( :provider, klass, :kind_of => [ Class ] ) end def action(arg=nil) if arg action_list = arg.kind_of?(Array) ? arg : [ arg ] action_list = action_list.collect { |a| a.to_sym } action_list.each do |action| validate( { :action => action, }, { :action => { :kind_of => Symbol, :equal_to => @allowed_actions }, } ) end @action = action_list else @action end end def name(name=nil) if !name.nil? raise ArgumentError, "name must be a string!" unless name.kind_of?(String) @name = name end @name end def noop(tf=nil) if !tf.nil? raise ArgumentError, "noop must be true or false!" unless tf == true || tf == false @noop = tf end @noop end def ignore_failure(arg=nil) set_or_return( :ignore_failure, arg, :kind_of => [ TrueClass, FalseClass ] ) end def retries(arg=nil) set_or_return( :retries, arg, :kind_of => Integer ) end def retry_delay(arg=nil) set_or_return( :retry_delay, arg, :kind_of => Integer ) end def epic_fail(arg=nil) ignore_failure(arg) end # Sets up a notification from this resource to the resource specified by +resource_spec+. def notifies(action, resource_spec, timing=:delayed) # when using old-style resources(:template => "/foo.txt") style, you # could end up with multiple resources. resources = [ resource_spec ].flatten resources.each do |resource| validate_resource_spec!(resource_spec) case timing.to_s when 'delayed' notifies_delayed(action, resource) when 'immediate', 'immediately' notifies_immediately(action, resource) else raise ArgumentError, "invalid timing: #{timing} for notifies(#{action}, #{resources.inspect}, #{timing}) resource #{self} "\ "Valid timings are: :delayed, :immediate, :immediately" end end true end # Iterates over all immediate and delayed notifications, calling # resolve_resource_reference on each in turn, causing them to # resolve lazy/forward references. def resolve_notification_references run_context.immediate_notifications(self).each { |n| n.resolve_resource_reference(run_context.resource_collection) } run_context.delayed_notifications(self).each {|n| n.resolve_resource_reference(run_context.resource_collection) } end def notifies_immediately(action, resource_spec) run_context.notifies_immediately(Notification.new(resource_spec, action, self)) end def notifies_delayed(action, resource_spec) run_context.notifies_delayed(Notification.new(resource_spec, action, self)) end def immediate_notifications run_context.immediate_notifications(self) end def delayed_notifications run_context.delayed_notifications(self) end def resources(*args) run_context.resource_collection.find(*args) end def subscribes(action, resources, timing=:delayed) resources = [resources].flatten resources.each do |resource| if resource.is_a?(String) resource = Chef::Resource.new(resource, run_context) end if resource.run_context.nil? resource.run_context = run_context end resource.notifies(action, self, timing) end true end def validate_resource_spec!(resource_spec) run_context.resource_collection.validate_lookup_spec!(resource_spec) end def is(*args) if args.size == 1 args.first else return *args end end def to_s "#{@resource_name}[#{@name}]" end def to_text ivars = instance_variables.map { |ivar| ivar.to_sym } - HIDDEN_IVARS text = "# Declared in #{@source_line}\n\n" text << self.class.dsl_name + "(\"#{name}\") do\n" ivars.each do |ivar| if (value = instance_variable_get(ivar)) && !(value.respond_to?(:empty?) && value.empty?) value_string = value.respond_to?(:to_text) ? value.to_text : value.inspect text << " #{ivar.to_s.sub(/^@/,'')} #{value_string}\n" end end [@not_if, @only_if].flatten.each do |conditional| text << " #{conditional.to_text}\n" end text << "end\n" end def inspect ivars = instance_variables.map { |ivar| ivar.to_sym } - FORBIDDEN_IVARS ivars.inject("<#{to_s}") do |str, ivar| str << " #{ivar}: #{instance_variable_get(ivar).inspect}" end << ">" end # as_json does most of the to_json heavy lifted. It exists here in case activesupport # is loaded. activesupport will call as_json and skip over to_json. This ensure # json is encoded as expected def as_json(*a) safe_ivars = instance_variables.map { |ivar| ivar.to_sym } - FORBIDDEN_IVARS instance_vars = Hash.new safe_ivars.each do |iv| instance_vars[iv.to_s.sub(/^@/, '')] = instance_variable_get(iv) end { 'json_class' => self.class.name, 'instance_vars' => instance_vars } end # Serialize this object as a hash def to_json(*a) results = as_json results.to_json(*a) end def to_hash safe_ivars = instance_variables.map { |ivar| ivar.to_sym } - FORBIDDEN_IVARS instance_vars = Hash.new safe_ivars.each do |iv| key = iv.to_s.sub(/^@/,'').to_sym instance_vars[key] = instance_variable_get(iv) end instance_vars end # If command is a block, returns true if the block returns true, false if it returns false. # ("Only run this resource if the block is true") # # If the command is not a block, executes the command. If it returns any status other than # 0, it returns false (clearly, a 0 status code is true) # # === Parameters # command:: A a string to execute. # opts:: Options control the execution of the command # block:: A ruby block to run. Ignored if a command is given. # # === Evaluation # * evaluates to true if the block is true, or if the command returns 0 # * evaluates to false if the block is false, or if the command returns a non-zero exit code. def only_if(command=nil, opts={}, &block) if command || block_given? @only_if << Conditional.only_if(command, opts, &block) end @only_if end # If command is a block, returns false if the block returns true, true if it returns false. # ("Do not run this resource if the block is true") # # If the command is not a block, executes the command. If it returns a 0 exitstatus, returns false. # ("Do not run this resource if the command returns 0") # # === Parameters # command:: A a string to execute. # opts:: Options control the execution of the command # block:: A ruby block to run. Ignored if a command is given. # # === Evaluation # * evaluates to true if the block is false, or if the command returns a non-zero exit status. # * evaluates to false if the block is true, or if the command returns a 0 exit status. def not_if(command=nil, opts={}, &block) if command || block_given? @not_if << Conditional.not_if(command, opts, &block) end @not_if end def defined_at # The following regexp should match these two sourceline formats: # /some/path/to/file.rb:80:in `wombat_tears' # C:/some/path/to/file.rb:80 in 1`wombat_tears' # extracting the path to the source file and the line number. (file, line_no) = source_line.match(/(.*):(\d+):?.*$/).to_a[1,2] if source_line if cookbook_name && recipe_name && source_line "#{cookbook_name}::#{recipe_name} line #{line_no}" elsif source_line "#{file} line #{line_no}" else "dynamically defined" end end def cookbook_version if cookbook_name run_context.cookbook_collection[cookbook_name] end end def events run_context.events end def run_action(action, notification_type=nil, notifying_resource=nil) # reset state in case of multiple actions on the same resource. @elapsed_time = 0 start_time = Time.now events.resource_action_start(self, action, notification_type, notifying_resource) # Try to resolve lazy/forward references in notifications again to handle # the case where the resource was defined lazily (ie. in a ruby_block) resolve_notification_references validate_action(action) if Chef::Config[:verbose_logging] || Chef::Log.level == :debug # This can be noisy Chef::Log.info("Processing #{self} action #{action} (#{defined_at})") end # ensure that we don't leave @updated_by_last_action set to true # on accident updated_by_last_action(false) begin return if should_skip?(action) provider_for_action(action).run_action rescue Exception => e if ignore_failure Chef::Log.error("#{self} (#{defined_at}) had an error: #{e.message}; ignore_failure is set, continuing") events.resource_failed(self, action, e) elsif retries > 0 events.resource_failed_retriable(self, action, retries, e) @retries -= 1 Chef::Log.info("Retrying execution of #{self}, #{retries} attempt(s) left") sleep retry_delay retry else events.resource_failed(self, action, e) raise customize_exception(e) end ensure @elapsed_time = Time.now - start_time events.resource_completed(self) end end def validate_action(action) raise ArgumentError, "nil is not a valid action for resource #{self}" if action.nil? end def provider_for_action(action) # leverage new platform => short_name => resource # which requires explicitly setting provider in # resource class if self.provider provider = self.provider.new(self, self.run_context) provider.action = action provider else # fall back to old provider resolution Chef::Platform.provider_for_resource(self, action) end end def customize_exception(e) new_exception = e.exception("#{self} (#{defined_at}) had an error: #{e.class.name}: #{e.message}") new_exception.set_backtrace(e.backtrace) new_exception end # Evaluates not_if and only_if conditionals. Returns a falsey value if any # of the conditionals indicate that this resource should be skipped, i.e., # if an only_if evaluates to false or a not_if evaluates to true. # # If this resource should be skipped, returns the first conditional that # "fails" its check. Subsequent conditionals are not evaluated, so in # general it's not a good idea to rely on side effects from not_if or # only_if commands/blocks being evaluated. # # Also skips conditional checking when the action is :nothing def should_skip?(action) conditional_action = ConditionalActionNotNothing.new(action) conditionals = [ conditional_action ] + only_if + not_if conditionals.find do |conditional| if conditional.continue? false else events.resource_skipped(self, action, conditional) Chef::Log.debug("Skipping #{self} due to #{conditional.description}") true end end end def updated_by_last_action(true_or_false) @updated ||= true_or_false @updated_by_last_action = true_or_false end def updated_by_last_action? @updated_by_last_action end def updated? updated end def self.json_create(o) resource = self.new(o["instance_vars"]["@name"]) o["instance_vars"].each do |k,v| resource.instance_variable_set("@#{k}".to_sym, v) end resource end # Hook to allow a resource to run specific code after creation def after_created nil end # Resources that want providers namespaced somewhere other than # Chef::Provider can set the namespace with +provider_base+ # Ex: # class MyResource < Chef::Resource # provider_base Chef::Provider::Deploy # # ...other stuff # end def self.provider_base(arg=nil) @provider_base ||= arg @provider_base ||= Chef::Provider end def self.platform_map @@platform_map ||= PlatformMap.new end # Maps a short_name (and optionally a platform and version) to a # Chef::Resource. This allows finer grained per platform resource # attributes and the end of overloaded resource definitions # (I'm looking at you Chef::Resource::Package) # Ex: # class WindowsFile < Chef::Resource # provides :file, :on_platforms => ["windows"] # # ...other stuff # end # # TODO: 2011-11-02 schisamo - platform_version support def self.provides(short_name, opts={}) short_name_sym = short_name if short_name.kind_of?(String) short_name.downcase! short_name.gsub!(/\s/, "_") short_name_sym = short_name.to_sym end if opts.has_key?(:on_platforms) platforms = [opts[:on_platforms]].flatten platforms.each do |p| p = :default if :all == p.to_sym platform_map.set( :platform => p.to_sym, :short_name => short_name_sym, :resource => self ) end else platform_map.set( :short_name => short_name_sym, :resource => self ) end end # Returns a resource based on a short_name anda platform and version. # # # ==== Parameters # short_name:: short_name of the resource (ie :directory) # platform:: platform name # version:: platform version # # === Returns # :: returns the proper Chef::Resource class def self.resource_for_platform(short_name, platform=nil, version=nil) platform_map.get(short_name, platform, version) end # Returns a resource based on a short_name and a node's # platform and version. # # ==== Parameters # short_name:: short_name of the resource (ie :directory) # node:: Node object to look up platform and version in # # === Returns # :: returns the proper Chef::Resource class def self.resource_for_node(short_name, node) begin platform, version = Chef::Platform.find_platform_and_version(node) rescue ArgumentError end resource = resource_for_platform(short_name, platform, version) resource end private def lookup_provider_constant(name) begin self.class.provider_base.const_get(convert_to_class_name(name.to_s)) rescue NameError => e if e.to_s =~ /#{Regexp.escape(self.class.provider_base.to_s)}/ raise ArgumentError, "No provider found to match '#{name}'" else raise e end end end end end chef-11.8.2/lib/chef/runner.rb0000644000004100000410000001002412254362222016046 0ustar www-datawww-data#-- # Author:: Adam Jacob () # Author:: Christopher Walters () # Author:: Tim Hinderliter () # Copyright:: Copyright (c) 2008, 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/exceptions' require 'chef/mixin/params_validate' require 'chef/node' require 'chef/resource_collection' class Chef # == Chef::Runner # This class is responsible for executing the steps in a Chef run. class Runner attr_reader :run_context attr_reader :delayed_actions include Chef::Mixin::ParamsValidate def initialize(run_context) @run_context = run_context @delayed_actions = [] end def events @run_context.events end # Determine the appropriate provider for the given resource, then # execute it. def run_action(resource, action, notification_type=nil, notifying_resource=nil) resource.run_action(action, notification_type, notifying_resource) # Execute any immediate and queue up any delayed notifications # associated with the resource, but only if it was updated *this time* # we ran an action on it. if resource.updated_by_last_action? run_context.immediate_notifications(resource).each do |notification| Chef::Log.info("#{resource} sending #{notification.action} action to #{notification.resource} (immediate)") run_action(notification.resource, notification.action, :immediate, resource) end run_context.delayed_notifications(resource).each do |notification| if delayed_actions.any? { |existing_notification| existing_notification.duplicates?(notification) } Chef::Log.info( "#{resource} not queuing delayed action #{notification.action} on #{notification.resource}"\ " (delayed), as it's already been queued") else delayed_actions << notification end end end end # Iterates over the +resource_collection+ in the +run_context+ calling # +run_action+ for each resource in turn. def converge # Resolve all lazy/forward references in notifications run_context.resource_collection.each do |resource| resource.resolve_notification_references end # Execute each resource. run_context.resource_collection.execute_each_resource do |resource| Array(resource.action).each {|action| run_action(resource, action)} end rescue Exception => e Chef::Log.info "Running queued delayed notifications before re-raising exception" run_delayed_notifications(e) else run_delayed_notifications(nil) true end private # Run all our :delayed actions def run_delayed_notifications(error=nil) collected_failures = Exceptions::MultipleFailures.new collected_failures.client_run_failure(error) unless error.nil? delayed_actions.each do |notification| result = run_delayed_notification(notification) if result.kind_of?(Exception) collected_failures.notification_failure(result) end end collected_failures.raise! end def run_delayed_notification(notification) Chef::Log.info( "#{notification.notifying_resource} sending #{notification.action}"\ " action to #{notification.resource} (delayed)") # Struct of resource/action to call run_action(notification.resource, notification.action, :delayed) true rescue Exception => e e end end end chef-11.8.2/lib/chef/shell/0000755000004100000410000000000012254362222015322 5ustar www-datawww-datachef-11.8.2/lib/chef/shell/shell_session.rb0000644000004100000410000001762612254362222020535 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Author:: Tim Hinderliter () # Copyright:: Copyright (c) 2009 Daniel DeLeo # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/recipe' require 'chef/run_context' require 'chef/config' require 'chef/client' require 'chef/cookbook/cookbook_collection' require 'chef/cookbook_loader' require 'chef/run_list/run_list_expansion' require 'chef/formatters/base' require 'chef/formatters/doc' require 'chef/formatters/minimal' module Shell class ShellSession include Singleton def self.session_type(type=nil) @session_type = type if type @session_type end attr_accessor :node, :compile, :recipe, :run_context attr_reader :node_attributes, :client def initialize @node_built = false formatter = Chef::Formatters.new(Chef::Config.formatter, STDOUT, STDERR) @events = Chef::EventDispatch::Dispatcher.new(formatter) end def node_built? !!@node_built end def reset! loading do rebuild_node @node = client.node shorten_node_inspect Shell::Extensions.extend_context_node(@node) rebuild_context node.consume_attributes(node_attributes) if node_attributes @recipe = Chef::Recipe.new(nil, nil, run_context) Shell::Extensions.extend_context_recipe(@recipe) @node_built = true end end def node_attributes=(attrs) @node_attributes = attrs @node.consume_attributes(@node_attributes) end def resource_collection run_context.resource_collection end def run_context @run_context ||= rebuild_context end def definitions nil end def cookbook_loader nil end def save_node raise "Not Supported! #{self.class.name} doesn't support #save_node, maybe you need to run chef-shell in client mode?" end def rebuild_context raise "Not Implemented! :rebuild_collection should be implemented by subclasses" end private def loading show_loading_progress begin yield rescue => e loading_complete(false) raise e else loading_complete(true) end end def show_loading_progress print "Loading" @loading = true @dot_printer = Thread.new do while @loading print "." sleep 0.5 end end end def loading_complete(success) @loading = false @dot_printer.join msg = success ? "done.\n\n" : "epic fail!\n\n" print msg end def shorten_node_inspect def @node.inspect "" end end def rebuild_node raise "Not Implemented! :rebuild_node should be implemented by subclasses" end end class StandAloneSession < ShellSession session_type :standalone def rebuild_context cookbook_collection = Chef::CookbookCollection.new({}) @run_context = Chef::RunContext.new(@node, cookbook_collection, @events) # no recipes @run_context.load(Chef::RunList::RunListExpansionFromDisk.new("_default", [])) # empty recipe list end private def rebuild_node Chef::Config[:solo] = true @client = Chef::Client.new @client.run_ohai @client.load_node @client.build_node end end class SoloSession < ShellSession session_type :solo def definitions @run_context.definitions end def rebuild_context @run_status = Chef::RunStatus.new(@node, @events) Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, Chef::Config[:cookbook_path]) } cl = Chef::CookbookLoader.new(Chef::Config[:cookbook_path]) cl.load_cookbooks cookbook_collection = Chef::CookbookCollection.new(cl) @run_context = Chef::RunContext.new(node, cookbook_collection, @events) @run_context.load(Chef::RunList::RunListExpansionFromDisk.new("_default", [])) @run_status.run_context = run_context end private def rebuild_node # Tell the client we're chef solo so it won't try to contact the server Chef::Config[:solo] = true @client = Chef::Client.new @client.run_ohai @client.load_node @client.build_node end end class ClientSession < SoloSession session_type :client def save_node @client.save_node end def rebuild_context @run_status = Chef::RunStatus.new(@node, @events) Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::RemoteFileVendor.new(manifest, Chef::REST.new(Chef::Config[:server_url])) } cookbook_hash = @client.sync_cookbooks cookbook_collection = Chef::CookbookCollection.new(cookbook_hash) @run_context = Chef::RunContext.new(node, cookbook_collection, @events) @run_context.load(@node.run_list.expand(@node.chef_environment)) @run_status.run_context = run_context end private def rebuild_node # Make sure the client knows this is not chef solo Chef::Config[:solo] = false @client = Chef::Client.new @client.run_ohai @client.register @client.load_node @client.build_node end end class DoppelGangerClient < Chef::Client attr_reader :node_name def initialize(node_name) @node_name = node_name @ohai = Ohai::System.new end # Run the very smallest amount of ohai we can get away with and still # hope to have things work. Otherwise we're not very good doppelgangers def run_ohai @ohai.require_plugin('os') end # DoppelGanger implementation of build_node. preserves as many of the node's # attributes, and does not save updates to the server def build_node Chef::Log.debug("Building node object for #{@node_name}") @node = Chef::Node.find_or_create(node_name) ohai_data = @ohai.data.merge(@node.automatic_attrs) @node.consume_external_attrs(ohai_data,nil) @run_list_expansion = @node.expand!('server') @expanded_run_list_with_versions = @run_list_expansion.recipes.with_version_constraints_strings Chef::Log.info("Run List is [#{@node.run_list}]") Chef::Log.info("Run List expands to [#{@expanded_run_list_with_versions.join(', ')}]") @node end def register @rest = Chef::REST.new(Chef::Config[:chef_server_url], Chef::Config[:node_name], Chef::Config[:client_key]) end end class DoppelGangerSession < ClientSession session_type "doppelganger client" def save_node puts "A doppelganger should think twice before saving the node" end def assume_identity(node_name) Chef::Config[:doppelganger] = @node_name = node_name reset! rescue Exception => e puts "#{e.class.name}: #{e.message}" puts Array(e.backtrace).join("\n") puts puts "* " * 40 puts "failed to assume the identity of node '#{node_name}', resetting" puts "* " * 40 puts Chef::Config[:doppelganger] = false @node_built = false Shell.session end def rebuild_node # Make sure the client knows this is not chef solo Chef::Config[:solo] = false @client = DoppelGangerClient.new(@node_name) @client.run_ohai @client.register @client.load_node @client.build_node @client.sync_cookbooks end end end chef-11.8.2/lib/chef/shell/ext.rb0000644000004100000410000004214712254362222016457 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009 Daniel DeLeo # License:: Apache License, Version 2.0 # # 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. # require 'tempfile' require 'chef/recipe' require 'fileutils' require 'chef/dsl/platform_introspection' require 'chef/version' require 'chef/shell/shell_session' require 'chef/shell/model_wrapper' require 'chef/shell/shell_rest' require 'chef/json_compat' module Shell module Extensions Help = Struct.new(:cmd, :desc, :explanation) # Extensions to be included in every 'main' object in chef-shell. # These objects are extended with this module. module ObjectCoreExtensions def ensure_session_select_defined # irb breaks if you prematurely define IRB::JobMangager # so these methods need to be defined at the latest possible time. unless jobs.respond_to?(:select_session_by_context) def jobs.select_session_by_context(&block) @jobs.select { |job| block.call(job[1].context.main)} end end unless jobs.respond_to?(:session_select) def jobs.select_shell_session(target_context) session = if target_context.kind_of?(Class) select_session_by_context { |main| main.kind_of?(target_context) } else select_session_by_context { |main| main.equal?(target_context) } end Array(session.first)[1] end end end def find_or_create_session_for(context_obj) ensure_session_select_defined if subsession = jobs.select_shell_session(context_obj) jobs.switch(subsession) else irb(context_obj) end end def help_banner banner = [] banner << "" banner << "chef-shell Help" banner << "".ljust(80, "=") banner << "| " + "Command".ljust(25) + "| " + "Description" banner << "".ljust(80, "=") self.all_help_descriptions.each do |help_text| banner << "| " + help_text.cmd.ljust(25) + "| " + help_text.desc end banner << "".ljust(80, "=") banner << "\n" banner << "Use help(:command) to get detailed help with individual commands" banner << "\n" banner.join("\n") end def explain_command(method_name) help = self.all_help_descriptions.find { |h| h.cmd.to_s == method_name.to_s } if help puts "" puts "Command: #{method_name}" puts "".ljust(80, "=") puts help.explanation || help.desc puts "".ljust(80, "=") puts "" else puts "" puts "command #{method_name} not found or no help available" puts "" end end # helpfully returns +:on+ so we can have sugary syntax like `tracing on' def on :on end # returns +:off+ so you can just do `tracing off' def off :off end def help_descriptions @help_descriptions ||= [] end def all_help_descriptions help_descriptions end def desc(help_text) @desc = help_text end def explain(explain_text) @explain = explain_text end def subcommands(subcommand_help={}) @subcommand_help = subcommand_help end def singleton_method_added(mname) if @desc help_descriptions << Help.new(mname.to_s, @desc.to_s, @explain) @desc, @explain = nil, nil end if @subcommand_help @subcommand_help.each do |subcommand, text| help_descriptions << Help.new("#{mname}.#{subcommand}", text.to_s, nil) end end @subcommand_help = {} end end module String def on_off_to_bool case self when "on" true when "off" false else self end end end module Symbol def on_off_to_bool self.to_s.on_off_to_bool end end module TrueClass def to_on_off_str "on" end def on_off_to_bool self end end module FalseClass def to_on_off_str "off" end def on_off_to_bool self end end # Methods that have associated help text need to be dynamically added # to the main irb objects, so we define them in a proc and later # instance_eval the proc in the object. ObjectUIExtensions = Proc.new do extend Shell::Extensions::ObjectCoreExtensions desc "prints this help message" explain(<<-E) ## SUMMARY ## When called with no argument, +help+ prints a table of all chef-shell commands. When called with an argument COMMAND, +help+ prints a detailed explanation of the command if available, or the description if no explanation is available. E def help(commmand=nil) if commmand explain_command(commmand) else puts help_banner end :ucanhaz_halp end alias :halp :help desc "prints information about chef" def version puts "This is the chef-shell.\n" + " Chef Version: #{::Chef::VERSION}\n" + " http://www.opscode.com/chef\n" + " http://wiki.opscode.com/display/chef/Home" :ucanhaz_automation end alias :shell :version desc "switch to recipe mode" def recipe_mode find_or_create_session_for Shell.session.recipe :recipe end desc "switch to attributes mode" def attributes_mode find_or_create_session_for Shell.session.node :attributes end desc "run chef using the current recipe" def run_chef Chef::Log.level = :debug session = Shell.session runrun = Chef::Runner.new(session.run_context).converge Chef::Log.level = :info runrun end desc "returns an object to control a paused chef run" subcommands :resume => "resume the chef run", :step => "run only the next resource", :skip_back => "move back in the run list", :skip_forward => "move forward in the run list" def chef_run Shell.session.resource_collection.iterator end desc "resets the current recipe" def reset Shell.session.reset! end desc "assume the identity of another node." def become_node(node_name) Shell::DoppelGangerSession.instance.assume_identity(node_name) :doppelganger end alias :doppelganger :become_node desc "turns printout of return values on or off" def echo(on_or_off) conf.echo = on_or_off.on_off_to_bool end desc "says if echo is on or off" def echo? puts "echo is #{conf.echo.to_on_off_str}" end desc "turns on or off tracing of execution. *verbose*" def tracing(on_or_off) conf.use_tracer = on_or_off.on_off_to_bool tracing? end alias :trace :tracing desc "says if tracing is on or off" def tracing? puts "tracing is #{conf.use_tracer.to_on_off_str}" end alias :trace? :tracing? desc "simple ls style command" def ls(directory) Dir.entries(directory) end end MainContextExtensions = Proc.new do desc "returns the current node (i.e., this host)" def node Shell.session.node end desc "pretty print the node's attributes" def ohai(key=nil) pp(key ? node.attribute[key] : node.attribute) end end RESTApiExtensions = Proc.new do desc "edit an object in your EDITOR" explain(<<-E) ## SUMMARY ## +edit(object)+ allows you to edit any object that can be converted to JSON. When finished editing, this method will return the edited object: new_node = edit(existing_node) ## EDITOR SELECTION ## chef-shell looks for an editor using the following logic 1. Looks for an EDITOR set by Shell.editor = "EDITOR" 2. Looks for an EDITOR configured in your chef-shell config file 3. Uses the value of the EDITOR environment variable E def edit(object) unless Shell.editor puts "Please set your editor with Shell.editor = \"vim|emacs|mate|ed\"" return :failburger end filename = "chef-shell-edit-#{object.class.name}-" if object.respond_to?(:name) filename += object.name elsif object.respond_to?(:id) filename += object.id end edited_data = Tempfile.open([filename, ".js"]) do |tempfile| tempfile.sync = true tempfile.puts Chef::JSONCompat.to_json(object) system("#{Shell.editor.to_s} #{tempfile.path}") tempfile.rewind tempfile.read end Chef::JSONCompat.from_json(edited_data) end desc "Find and edit API clients" explain(<<-E) ## SUMMARY ## +clients+ allows you to query you chef server for information about your api clients. ## LIST ALL CLIENTS ## To see all clients on the system, use clients.all #=> [, ...] If the output from all is too verbose, or you're only interested in a specific value from each of the objects, you can give a code block to +all+: clients.all { |client| client.name } #=> [CLIENT1_NAME, CLIENT2_NAME, ...] ## SHOW ONE CLIENT ## To see a specific client, use clients.show(CLIENT_NAME) ## SEARCH FOR CLIENTS ## You can also search for clients using +find+ or +search+. You can use the familiar string search syntax: clients.search("KEY:VALUE") Just as the +all+ subcommand, the +search+ subcommand can use a code block to filter or transform the information returned from the search: clients.search("KEY:VALUE") { |c| c.name } You can also use a Hash based syntax, multiple search conditions will be joined with AND. clients.find :KEY => :VALUE, :KEY2 => :VALUE2, ... ## BULK-EDIT CLIENTS ## **BE CAREFUL, THIS IS DESTRUCTIVE** You can bulk edit API Clients using the +transform+ subcommand, which requires a code block. Each client will be saved after the code block is run. If the code block returns +nil+ or +false+, that client will be skipped: clients.transform("*:*") do |client| if client.name =~ /borat/i client.admin(false) true else nil end end This will strip the admin privileges from any client named after borat. E subcommands :all => "list all api clients", :show => "load an api client by name", :search => "search for API clients", :transform => "edit all api clients via a code block and save them" def clients @clients ||= Shell::ModelWrapper.new(Chef::ApiClient, :client) end desc "Find and edit cookbooks" subcommands :all => "list all cookbooks", :show => "load a cookbook by name", :transform => "edit all cookbooks via a code block and save them" def cookbooks @cookbooks ||= Shell::ModelWrapper.new(Chef::CookbookVersion) end desc "Find and edit nodes via the API" explain(<<-E) ## SUMMARY ## +nodes+ Allows you to query your chef server for information about your nodes. ## LIST ALL NODES ## You can list all nodes using +all+ or +list+ nodes.all #=> [, , ...] To limit the information returned for each node, pass a code block to the +all+ subcommand: nodes.all { |node| node.name } #=> [NODE1_NAME, NODE2_NAME, ...] ## SHOW ONE NODE ## You can show the data for a single node using the +show+ subcommand: nodes.show("NODE_NAME") => ## SEARCH FOR NODES ## You can search for nodes using the +search+ or +find+ subcommands: nodes.find(:name => "app*") #=> [, ...] Similarly to +all+, you can pass a code block to limit or transform the information returned: nodes.find(:name => "app#") { |node| node.ec2 } ## BULK EDIT NODES ## **BE CAREFUL, THIS OPERATION IS DESTRUCTIVE** Bulk edit nodes by passing a code block to the +transform+ or +bulk_edit+ subcommand. The block will be applied to each matching node, and then the node will be saved. If the block returns +nil+ or +false+, that node will be skipped. nodes.transform do |node| if node.fqdn =~ /.*\\.preprod\\.example\\.com/ node.set[:environment] = "preprod" end end This will assign the attribute to every node with a FQDN matching the regex. E subcommands :all => "list all nodes", :show => "load a node by name", :search => "search for nodes", :transform => "edit all nodes via a code block and save them" def nodes @nodes ||= Shell::ModelWrapper.new(Chef::Node) end desc "Find and edit roles via the API" explain(<<-E) ## SUMMARY ## +roles+ allows you to query and edit roles on your Chef server. ## SUBCOMMANDS ## * all (list) * show (load) * search (find) * transform (bulk_edit) ## SEE ALSO ## See the help for +nodes+ for more information about the subcommands. E subcommands :all => "list all roles", :show => "load a role by name", :search => "search for roles", :transform => "edit all roles via a code block and save them" def roles @roles ||= Shell::ModelWrapper.new(Chef::Role) end desc "Find and edit +databag_name+ via the api" explain(<<-E) ## SUMMARY ## +databags(DATABAG_NAME)+ allows you to query and edit data bag items on your Chef server. Unlike other commands for working with data on the server, +databags+ requires the databag name as an argument, for example: databags(:users).all ## SUBCOMMANDS ## * all (list) * show (load) * search (find) * transform (bulk_edit) ## SEE ALSO ## See the help for +nodes+ for more information about the subcommands. E subcommands :all => "list all items in the data bag", :show => "load a data bag item by id", :search => "search for items in the data bag", :transform => "edit all items via a code block and save them" def databags(databag_name) @named_databags_wrappers ||= {} @named_databags_wrappers[databag_name] ||= Shell::NamedDataBagWrapper.new(databag_name) end desc "Find and edit environments via the API" explain(<<-E) ## SUMMARY ## +environments+ allows you to query and edit environments on your Chef server. ## SUBCOMMANDS ## * all (list) * show (load) * search (find) * transform (bulk_edit) ## SEE ALSO ## See the help for +nodes+ for more information about the subcommands. E subcommands :all => "list all environments", :show => "load an environment by name", :search => "search for environments", :transform => "edit all environments via a code block and save them" def environments @environments ||= Shell::ModelWrapper.new(Chef::Environment) end desc "A REST Client configured to authenticate with the API" def api @rest = Shell::ShellREST.new(Chef::Config[:chef_server_url]) end end RecipeUIExtensions = Proc.new do alias :original_resources :resources desc "list all the resources on the current recipe" def resources(*args) if args.empty? pp run_context.resource_collection.instance_variable_get(:@resources_by_name).keys else pp resources = original_resources(*args) resources end end end def self.extend_context_object(obj) obj.instance_eval(&ObjectUIExtensions) obj.instance_eval(&MainContextExtensions) obj.instance_eval(&RESTApiExtensions) obj.extend(FileUtils) obj.extend(Chef::DSL::PlatformIntrospection) obj.extend(Chef::DSL::DataQuery) end def self.extend_context_node(node_obj) node_obj.instance_eval(&ObjectUIExtensions) end def self.extend_context_recipe(recipe_obj) recipe_obj.instance_eval(&ObjectUIExtensions) recipe_obj.instance_eval(&RecipeUIExtensions) end end end class String include Shell::Extensions::String end class Symbol include Shell::Extensions::Symbol end class TrueClass include Shell::Extensions::TrueClass end class FalseClass include Shell::Extensions::FalseClass end chef-11.8.2/lib/chef/shell/shell_rest.rb0000644000004100000410000000153012254362222020012 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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 Shell class ShellREST < Chef::REST alias :get :get_rest alias :put :put_rest alias :post :post_rest alias :delete :delete_rest end end chef-11.8.2/lib/chef/shell/model_wrapper.rb0000644000004100000410000000554312254362222020516 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/mixin/convert_to_class_name' require 'chef/mixin/language' module Shell class ModelWrapper include Chef::Mixin::ConvertToClassName attr_reader :model_symbol def initialize(model_class, symbol=nil) @model_class = model_class @model_symbol = symbol || convert_to_snake_case(model_class.name, "Chef").to_sym end def search(query) return all if query.to_s == "all" results = [] Chef::Search::Query.new.search(@model_symbol, format_query(query)) do |obj| if block_given? results << yield(obj) else results << obj end end results end alias :find :search def all(&block) all_objects = list_objects block_given? ? all_objects.map(&block) : all_objects end alias :list :all def show(obj_id) @model_class.load(obj_id) end alias :load :show def transform(what_to_transform, &block) if what_to_transform == :all objects_to_transform = list_objects else objects_to_transform = search(what_to_transform) end objects_to_transform.each do |obj| if result = yield(obj) obj.save end end end alias :bulk_edit :transform private # paper over inconsistencies in the model classes APIs, and return the objects # the user wanted instead of the URI=>object stuff def list_objects objects = @model_class.method(:list).arity == 0? @model_class.list : @model_class.list(true) objects.map { |obj| Array(obj).find {|o| o.kind_of?(@model_class)} } end def format_query(query) if query.respond_to?(:keys) query.map { |key, value| "#{key}:#{value}" }.join(" AND ") else query end end end class NamedDataBagWrapper < ModelWrapper def initialize(databag_name) @model_symbol = @databag_name = databag_name end alias :list :all def show(item) Chef::DataBagItem.load(@databag_name, item) end private def list_objects all_items = [] Chef::Search::Query.new.search(@databag_name) do |item| all_items << item end all_items end end end chef-11.8.2/lib/chef/daemon.rb0000644000004100000410000001031412254362222016002 0ustar www-datawww-data# # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # I love you Merb (lib/merb-core/server.rb) require 'chef/config' require 'chef/run_lock' require 'etc' class Chef class Daemon class << self attr_accessor :name attr_accessor :runlock # Daemonize the current process, managing pidfiles and process uid/gid # # === Parameters # name:: The name to be used for the pid file # def daemonize(name) @name = name @runlock = RunLock.new(pid_file) if runlock.test # We've acquired the daemon lock. Now daemonize. Chef::Log.info("Daemonizing..") begin exit if fork Process.setsid exit if fork Chef::Log.info("Forked, in #{Process.pid}. Privileges: #{Process.euid} #{Process.egid}") File.umask Chef::Config[:umask] $stdin.reopen("/dev/null") $stdout.reopen("/dev/null", "a") $stderr.reopen($stdout) runlock.save_pid rescue NotImplementedError => e Chef::Application.fatal!("There is no fork: #{e.message}") end else Chef::Application.fatal!("Chef is already running pid #{pid_from_file}") end end # Gets the pid file for @name # ==== Returns # String:: # Location of the pid file for @name def pid_file Chef::Config[:pid_file] or "/tmp/#{@name}.pid" end # Suck the pid out of pid_file # ==== Returns # Integer:: # The PID from pid_file # nil:: # Returned if the pid_file does not exist. # def pid_from_file File.read(pid_file).chomp.to_i rescue Errno::ENOENT, Errno::EACCES nil end # Change process user/group to those specified in Chef::Config # def change_privilege Dir.chdir("/") if Chef::Config[:user] and Chef::Config[:group] Chef::Log.info("About to change privilege to #{Chef::Config[:user]}:#{Chef::Config[:group]}") _change_privilege(Chef::Config[:user], Chef::Config[:group]) elsif Chef::Config[:user] Chef::Log.info("About to change privilege to #{Chef::Config[:user]}") _change_privilege(Chef::Config[:user]) end end # Change privileges of the process to be the specified user and group # # ==== Parameters # user:: The user to change the process to. # group:: The group to change the process to. # # ==== Alternatives # If group is left out, the user will be used (changing to user:user) # def _change_privilege(user, group=user) uid, gid = Process.euid, Process.egid begin target_uid = Etc.getpwnam(user).uid rescue ArgumentError => e Chef::Application.fatal!("Failed to get UID for user #{user}, does it exist? #{e.message}") return false end begin target_gid = Etc.getgrnam(group).gid rescue ArgumentError => e Chef::Application.fatal!("Failed to get GID for group #{group}, does it exist? #{e.message}") return false end if (uid != target_uid) or (gid != target_gid) Process.initgroups(user, target_gid) Process::GID.change_privilege(target_gid) Process::UID.change_privilege(target_uid) end true rescue Errno::EPERM => e Chef::Application.fatal!("Permission denied when trying to change #{uid}:#{gid} to #{target_uid}:#{target_gid}. #{e.message}") end end end end chef-11.8.2/lib/chef/environment.rb0000644000004100000410000002152512254362222017111 0ustar www-datawww-data# # Author:: Stephen Delano () # Author:: Seth Falcon () # Author:: John Keiser () # Author:: Kyle Goodwin () # Copyright:: Copyright 2010-2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/config' require 'chef/mash' require 'chef/mixin/params_validate' require 'chef/mixin/from_file' require 'chef/version_constraint' class Chef class Environment DEFAULT = "default" include Chef::Mixin::ParamsValidate include Chef::Mixin::FromFile COMBINED_COOKBOOK_CONSTRAINT = /(.+)(?:[\s]+)((?:#{Chef::VersionConstraint::OPS.join('|')})(?:[\s]+).+)$/.freeze def initialize @name = '' @description = '' @default_attributes = Mash.new @override_attributes = Mash.new @cookbook_versions = Hash.new end def chef_server_rest Chef::REST.new(Chef::Config[:chef_server_url]) end def self.chef_server_rest Chef::REST.new(Chef::Config[:chef_server_url]) end def name(arg=nil) set_or_return( :name, arg, { :regex => /^[\-[:alnum:]_]+$/, :kind_of => String } ) end def description(arg=nil) set_or_return( :description, arg, :kind_of => String ) end def default_attributes(arg=nil) set_or_return( :default_attributes, arg, :kind_of => Hash ) end def default_attributes=(attrs) default_attributes(attrs) end def override_attributes(arg=nil) set_or_return( :override_attributes, arg, :kind_of => Hash ) end def override_attributes=(attrs) override_attributes(attrs) end def cookbook_versions(arg=nil) set_or_return( :cookbook_versions, arg, { :kind_of => Hash, :callbacks => { "should be a valid set of cookbook version requirements" => lambda { |cv| Chef::Environment.validate_cookbook_versions(cv) } } } ) end def cookbook(cookbook, version) validate({ :version => version },{ :version => { :callbacks => { "should be a valid version requirement" => lambda { |v| Chef::Environment.validate_cookbook_version(v) } } } }) @cookbook_versions[cookbook] = version end def to_hash result = { "name" => @name, "description" => @description, "cookbook_versions" => @cookbook_versions, "json_class" => self.class.name, "chef_type" => "environment", "default_attributes" => @default_attributes, "override_attributes" => @override_attributes } result end def to_json(*a) to_hash.to_json(*a) end def update_from!(o) description(o.description) cookbook_versions(o.cookbook_versions) default_attributes(o.default_attributes) override_attributes(o.override_attributes) self end def update_attributes_from_params(params) unless params[:default_attributes].nil? || params[:default_attributes].size == 0 default_attributes(Chef::JSONCompat.from_json(params[:default_attributes])) end unless params[:override_attributes].nil? || params[:override_attributes].size == 0 override_attributes(Chef::JSONCompat.from_json(params[:override_attributes])) end end def update_from_params(params) # reset because everything we need will be in the params, this is necessary because certain constraints # may have been removed in the params and need to be removed from cookbook_versions as well. bkup_cb_versions = cookbook_versions cookbook_versions(Hash.new) valid = true begin name(params[:name]) rescue Chef::Exceptions::ValidationFailed => e invalid_fields[:name] = e.message valid = false end description(params[:description]) unless params[:cookbook_version].nil? params[:cookbook_version].each do |index, cookbook_constraint_spec| unless (cookbook_constraint_spec.nil? || cookbook_constraint_spec.size == 0) valid = valid && update_cookbook_constraint_from_param(index, cookbook_constraint_spec) end end end update_attributes_from_params(params) valid = validate_required_attrs_present && valid cookbook_versions(bkup_cb_versions) unless valid # restore the old cookbook_versions if valid is false valid end def update_cookbook_constraint_from_param(index, cookbook_constraint_spec) valid = true md = cookbook_constraint_spec.match(COMBINED_COOKBOOK_CONSTRAINT) if md.nil? || md[2].nil? valid = false add_cookbook_constraint_error(index, cookbook_constraint_spec) elsif self.class.validate_cookbook_version(md[2]) cookbook_versions[md[1]] = md[2] else valid = false add_cookbook_constraint_error(index, cookbook_constraint_spec) end valid end def add_cookbook_constraint_error(index, cookbook_constraint_spec) invalid_fields[:cookbook_version] ||= {} invalid_fields[:cookbook_version][index] = "#{cookbook_constraint_spec} is not a valid cookbook constraint" end def invalid_fields @invalid_fields ||= {} end def validate_required_attrs_present if name.nil? || name.size == 0 invalid_fields[:name] ||= "name cannot be empty" false else true end end def self.json_create(o) environment = new environment.name(o["name"]) environment.description(o["description"]) environment.cookbook_versions(o["cookbook_versions"]) environment.default_attributes(o["default_attributes"]) environment.override_attributes(o["override_attributes"]) environment end def self.list(inflate=false) if inflate response = Hash.new Chef::Search::Query.new.search(:environment) do |e| response[e.name] = e unless e.nil? end response else chef_server_rest.get_rest("environments") end end def self.load(name) if Chef::Config[:solo] load_from_file(name) else chef_server_rest.get_rest("environments/#{name}") end end def self.load_from_file(name) unless File.directory?(Chef::Config[:environment_path]) raise Chef::Exceptions::InvalidEnvironmentPath, "Environment path '#{Chef::Config[:environment_path]}' is invalid" end js_file = File.join(Chef::Config[:environment_path], "#{name}.json") rb_file = File.join(Chef::Config[:environment_path], "#{name}.rb") if File.exists?(js_file) # from_json returns object.class => json_class in the JSON. Chef::JSONCompat.from_json(IO.read(js_file)) elsif File.exists?(rb_file) environment = Chef::Environment.new environment.name(name) environment.from_file(rb_file) environment else raise Chef::Exceptions::EnvironmentNotFound, "Environment '#{name}' could not be loaded from disk" end end def destroy chef_server_rest.delete_rest("environments/#{@name}") end def save begin chef_server_rest.put_rest("environments/#{@name}", self) rescue Net::HTTPServerException => e raise e unless e.response.code == "404" chef_server_rest.post_rest("environments", self) end self end def create chef_server_rest.post_rest("environments", self) self end def self.load_filtered_recipe_list(environment) chef_server_rest.get_rest("environments/#{environment}/recipes") end def to_s @name end def self.validate_cookbook_versions(cv) return false unless cv.kind_of?(Hash) cv.each do |cookbook, version| return false unless Chef::Environment.validate_cookbook_version(version) end true end def self.validate_cookbook_version(version) begin if Chef::Config[:solo] raise Chef::Exceptions::IllegalVersionConstraint, "Environment cookbook version constraints not allowed in chef-solo" else Chef::VersionConstraint.new version true end rescue ArgumentError false end end end end chef-11.8.2/lib/chef/data_bag.rb0000644000004100000410000001003212254362222016256 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Nuo Yan () # Author:: Christopher Brown () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/config' require 'chef/mixin/params_validate' require 'chef/mixin/from_file' require 'chef/data_bag_item' require 'chef/mash' require 'chef/json_compat' class Chef class DataBag include Chef::Mixin::FromFile include Chef::Mixin::ParamsValidate VALID_NAME = /^[\-[:alnum:]_]+$/ def self.validate_name!(name) unless name =~ VALID_NAME raise Exceptions::InvalidDataBagName, "DataBags must have a name matching #{VALID_NAME.inspect}, you gave #{name.inspect}" end end # Create a new Chef::DataBag def initialize @name = '' end def name(arg=nil) set_or_return( :name, arg, :regex => VALID_NAME ) end def to_hash result = { "name" => @name, 'json_class' => self.class.name, "chef_type" => "data_bag", } result end # Serialize this object as a hash def to_json(*a) to_hash.to_json(*a) end def chef_server_rest Chef::REST.new(Chef::Config[:chef_server_url]) end def self.chef_server_rest Chef::REST.new(Chef::Config[:chef_server_url]) end # Create a Chef::Role from JSON def self.json_create(o) bag = new bag.name(o["name"]) bag end def self.list(inflate=false) if Chef::Config[:solo] unless File.directory?(Chef::Config[:data_bag_path]) raise Chef::Exceptions::InvalidDataBagPath, "Data bag path '#{Chef::Config[:data_bag_path]}' is invalid" end names = Dir.glob(File.join(Chef::Config[:data_bag_path], "*")).map{|f|File.basename(f)}.sort names.inject({}) {|h, n| h[n] = n; h} else if inflate # Can't search for all data bags like other objects, fall back to N+1 :( list(false).inject({}) do |response, bag_and_uri| response[bag_and_uri.first] = load(bag_and_uri.first) response end else Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("data") end end end # Load a Data Bag by name via either the RESTful API or local data_bag_path if run in solo mode def self.load(name) if Chef::Config[:solo] unless File.directory?(Chef::Config[:data_bag_path]) raise Chef::Exceptions::InvalidDataBagPath, "Data bag path '#{Chef::Config[:data_bag_path]}' is invalid" end Dir.glob(File.join(Chef::Config[:data_bag_path], "#{name}", "*.json")).inject({}) do |bag, f| item = Chef::JSONCompat.from_json(IO.read(f)) bag[item['id']] = item bag end else Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("data/#{name}") end end def destroy chef_server_rest.delete_rest("data/#{@name}") end # Save the Data Bag via RESTful API def save begin if Chef::Config[:why_run] Chef::Log.warn("In whyrun mode, so NOT performing data bag save.") else create end rescue Net::HTTPServerException => e raise e unless e.response.code == "409" end self end #create a data bag via RESTful API def create chef_server_rest.post_rest("data", self) self end # As a string def to_s "data_bag[#{@name}]" end end end chef-11.8.2/lib/chef/resource_definition.rb0000644000004100000410000000371012254362222020600 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/mixin/from_file' require 'chef/mixin/params_validate' class Chef class ResourceDefinition include Chef::Mixin::FromFile include Chef::Mixin::ParamsValidate attr_accessor :name, :params, :recipe, :node def initialize(node=nil) @name = nil @params = Hash.new @recipe = nil @node = node end def define(resource_name, prototype_params=nil, &block) unless resource_name.kind_of?(Symbol) raise ArgumentError, "You must use a symbol when defining a new resource!" end @name = resource_name if prototype_params unless prototype_params.kind_of?(Hash) raise ArgumentError, "You must pass a hash as the prototype parameters for a definition." end @params = prototype_params end if Kernel.block_given? @recipe = block else raise ArgumentError, "You must pass a block to a definition." end true end # When we do the resource definition, we're really just setting new values for # the paramaters we prototyped at the top. This method missing is as simple as # it gets. def method_missing(symbol, *args) @params[symbol] = args.length == 1 ? args[0] : args end def to_s "#{name.to_s}" end end end chef-11.8.2/lib/chef/http/0000755000004100000410000000000012254362222015172 5ustar www-datawww-datachef-11.8.2/lib/chef/http/http_request.rb0000644000004100000410000001167312254362222020256 0ustar www-datawww-data#-- # Author:: Adam Jacob () # Author:: Thom May () # Author:: Nuo Yan () # Author:: Christopher Brown () # Author:: Christopher Walters () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009, 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'uri' require 'net/http' # To load faster, we only want ohai's version string. # However, in ohai before 0.6.0, the version is defined # in ohai, not ohai/version begin require 'ohai/version' #used in user agent string. rescue LoadError require 'ohai' end require 'chef/version' class Chef class HTTP class HTTPRequest engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : "ruby" UA_COMMON = "/#{::Chef::VERSION} (#{engine}-#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}; ohai-#{Ohai::VERSION}; #{RUBY_PLATFORM}; +http://opscode.com)" DEFAULT_UA = "Chef Client" << UA_COMMON USER_AGENT = "User-Agent".freeze ACCEPT_ENCODING = "Accept-Encoding".freeze ENCODING_GZIP_DEFLATE = "gzip;q=1.0,deflate;q=0.6,identity;q=0.3".freeze GET = "get".freeze PUT = "put".freeze POST = "post".freeze DELETE = "delete".freeze HEAD = "head".freeze HTTPS = "https".freeze SLASH = "/".freeze def self.user_agent=(ua) @user_agent = ua end def self.user_agent @user_agent ||= DEFAULT_UA end attr_reader :method, :url, :headers, :http_client, :http_request def initialize(method, url, req_body, base_headers={}) @method, @url = method, url @request_body = nil build_headers(base_headers) configure_http_request(req_body) end def host @url.host end def port @url.port end def query @url.query end def path @url.path.empty? ? SLASH : @url.path end # DEPRECATED. Call request on an HTTP client object instead. def call hide_net_http_bug do http_client.request(http_request) do |response| yield response if block_given? response end end end def config Chef::Config end # DEPRECATED. Call request on an HTTP client object instead. def http_client @http_client ||= BasicClient.new(url).http_client end private def hide_net_http_bug yield rescue NoMethodError => e # http://redmine.ruby-lang.org/issues/show/2708 # http://redmine.ruby-lang.org/issues/show/2758 if e.to_s =~ /#{Regexp.escape(%q|undefined method `closed?' for nil:NilClass|)}/ Chef::Log.debug("Rescued error in http connect, re-raising as Errno::ECONNREFUSED to hide bug in net/http") Chef::Log.debug("#{e.class.name}: #{e.to_s}") Chef::Log.debug(e.backtrace.join("\n")) raise Errno::ECONNREFUSED, "Connection refused attempting to contact #{url.scheme}://#{host}:#{port}" else raise end end def build_headers(headers) @headers = headers.dup # No response compression unless we asked for it explicitly: @headers[HTTPRequest::ACCEPT_ENCODING] ||= "identity" @headers['X-Chef-Version'] = ::Chef::VERSION @headers end def configure_http_request(request_body=nil) req_path = "#{path}" req_path << "?#{query}" if query @http_request = case method.to_s.downcase when GET Net::HTTP::Get.new(req_path, headers) when POST Net::HTTP::Post.new(req_path, headers) when PUT Net::HTTP::Put.new(req_path, headers) when DELETE Net::HTTP::Delete.new(req_path, headers) when HEAD Net::HTTP::Head.new(req_path, headers) else raise ArgumentError, "You must provide :GET, :PUT, :POST, :DELETE or :HEAD as the method" end @http_request.body = request_body if (request_body && @http_request.request_body_permitted?) # Optionally handle HTTP Basic Authentication if url.user user = URI.unescape(url.user) password = URI.unescape(url.password) if url.password @http_request.basic_auth(user, password) end # Overwrite default UA @http_request[USER_AGENT] = self.class.user_agent end end end end chef-11.8.2/lib/chef/http/auth_credentials.rb0000644000004100000410000000415712254362222021044 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Thom May () # Author:: Nuo Yan () # Author:: Christopher Brown () # Author:: Christopher Walters () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009, 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/log' require 'mixlib/authentication/signedheaderauth' class Chef class HTTP class AuthCredentials attr_reader :client_name, :key def initialize(client_name=nil, key=nil) @client_name, @key = client_name, key end def sign_requests? !!key end def signature_headers(request_params={}) raise ArgumentError, "Cannot sign the request without a client name, check that :node_name is assigned" if client_name.nil? Chef::Log.debug("Signing the request as #{client_name}") # params_in = {:http_method => :GET, :path => "/clients", :body => "", :host => "localhost"} request_params = request_params.dup request_params[:timestamp] = Time.now.utc.iso8601 request_params[:user_id] = client_name request_params[:proto_version] = Chef::Config[:authentication_protocol_version] host = request_params.delete(:host) || "localhost" sign_obj = Mixlib::Authentication::SignedHeaderAuth.signing_object(request_params) signed = sign_obj.sign(key).merge({:host => host}) signed.inject({}){|memo, kv| memo["#{kv[0].to_s.upcase}"] = kv[1];memo} end end end end chef-11.8.2/lib/chef/http/simple.rb0000644000004100000410000000031512254362222017007 0ustar www-datawww-datarequire 'chef/http' require 'chef/http/authenticator' require 'chef/http/decompressor' class Chef class HTTP class Simple < HTTP use Decompressor use CookieManager end end end chef-11.8.2/lib/chef/http/cookie_manager.rb0000644000004100000410000000331412254362222020463 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/http/cookie_jar' class Chef class HTTP # An HTTP middleware to manage storing/sending cookies in HTTP requests. # Most HTTP communication in Chef does not need cookies, it was originally # implemented to support OpenID, but it's not known who might be relying on # it, so it's included with Chef::REST class CookieManager def initialize(options={}) @cookies = CookieJar.instance end def handle_request(method, url, headers={}, data=false) @host, @port = url.host, url.port if @cookies.has_key?("#{@host}:#{@port}") headers['Cookie'] = @cookies["#{@host}:#{@port}"] end [method, url, headers, data] end def handle_response(http_response, rest_request, return_value) if http_response['set-cookie'] @cookies["#{@host}:#{@port}"] = http_response['set-cookie'] end [http_response, rest_request, return_value] end def stream_response_handler(response) nil end end end end chef-11.8.2/lib/chef/http/json_output.rb0000644000004100000410000000465312254362222020120 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/json_compat' require 'chef/log' class Chef class HTTP # Middleware that takes an HTTP response, parses it as JSON if possible. class JSONOutput def initialize(opts={}) @raw_output = opts[:raw_output] @inflate_json_class = opts[:inflate_json_class] end def handle_request(method, url, headers={}, data=false) # Ideally this should always set Accept to application/json, but # Chef::REST is sometimes used to make non-JSON requests, so it sets # Accept to the desired value before middlewares get called. headers['Accept'] ||= 'application/json' [method, url, headers, data] end def handle_response(http_response, rest_request, return_value) # temporary hack, skip processing if return_value is false # needed to keep conditional get stuff working correctly. return [http_response, rest_request, return_value] if return_value == false if http_response['content-type'] =~ /json/ if @raw_output return_value = http_response.body.to_s else if @inflate_json_class return_value = Chef::JSONCompat.from_json(http_response.body.chomp) else return_value = Chef::JSONCompat.from_json(http_response.body.chomp, :create_additions => false) end end [http_response, rest_request, return_value] else Chef::Log.debug("Expected JSON response, but got content-type '#{http_response['content-type']}'") return [http_response, rest_request, http_response.body.to_s] end end def stream_response_handler(response) nil end end end end chef-11.8.2/lib/chef/http/basic_client.rb0000644000004100000410000000723112254362222020141 0ustar www-datawww-data#-- # Author:: Adam Jacob () # Author:: Thom May () # Author:: Nuo Yan () # Author:: Christopher Brown () # Author:: Christopher Walters () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009, 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'uri' require 'net/http' require 'chef/http/ssl_policies' require 'chef/http/http_request' class Chef class HTTP class BasicClient HTTPS = "https".freeze attr_reader :url attr_reader :http_client attr_reader :ssl_policy # Instantiate a BasicClient. # === Arguments: # url:: An URI for the remote server. # === Options: # ssl_policy:: The SSL Policy to use, defaults to DefaultSSLPolicy def initialize(url, opts={}) @url = url @ssl_policy = opts[:ssl_policy] || DefaultSSLPolicy @http_client = build_http_client end def host @url.host end def port @url.port end def request(method, url, req_body, base_headers={}) http_request = HTTPRequest.new(method, url, req_body, base_headers).http_request Chef::Log.debug("Initiating #{method} to #{url}") Chef::Log.debug("---- HTTP Request Header Data: ----") base_headers.each do |name, value| Chef::Log.debug("#{name}: #{value}") end http_client.request(http_request) do |response| yield response if block_given? # http_client.request may not have the return signature we want, so # force the issue: return [http_request, response] end rescue OpenSSL::SSL::SSLError => e Chef::Log.error("SSL Validation failure connecting to host: #{host} - #{e.message}") raise end #adapted from buildr/lib/buildr/core/transports.rb def proxy_uri proxy = Chef::Config["#{url.scheme}_proxy"] proxy = URI.parse(proxy) if String === proxy excludes = Chef::Config[:no_proxy].to_s.split(/\s*,\s*/).compact excludes = excludes.map { |exclude| exclude =~ /:\d+$/ ? exclude : "#{exclude}:*" } return proxy unless excludes.any? { |exclude| File.fnmatch(exclude, "#{host}:#{port}") } end def build_http_client http_client = http_client_builder.new(host, port) if url.scheme == HTTPS configure_ssl(http_client) end http_client.read_timeout = config[:rest_timeout] http_client end def config Chef::Config end def http_client_builder http_proxy = proxy_uri if http_proxy.nil? Net::HTTP else Chef::Log.debug("Using #{http_proxy.host}:#{http_proxy.port} for proxy") user = Chef::Config["#{url.scheme}_proxy_user"] pass = Chef::Config["#{url.scheme}_proxy_pass"] Net::HTTP.Proxy(http_proxy.host, http_proxy.port, user, pass) end end def configure_ssl(http_client) http_client.use_ssl = true ssl_policy.apply_to(http_client) end end end end chef-11.8.2/lib/chef/http/json_to_model_output.rb0000644000004100000410000000214012254362222021767 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/http/json_output' class Chef class HTTP # A Middleware-ish thing that takes an HTTP response, parses it as JSON if # possible, and converts it into an appropriate model object if it contains # a `json_class` key. class JSONToModelOutput < JSONOutput def initialize(opts={}) opts[:inflate_json_class] = true if !opts.has_key?(:inflate_json_class) super end end end end chef-11.8.2/lib/chef/http/ssl_policies.rb0000644000004100000410000001042312254362222020207 0ustar www-datawww-data#-- # Author:: Adam Jacob () # Author:: Thom May () # Author:: Nuo Yan () # Author:: Christopher Brown () # Author:: Christopher Walters () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009, 2010, 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'openssl' class Chef class HTTP # == Chef::HTTP::DefaultSSLPolicy # Configures SSL behavior on an HTTP object via visitor pattern. class DefaultSSLPolicy def self.apply_to(http_client) new(http_client).apply http_client end attr_reader :http_client def initialize(http_client) @http_client = http_client end def apply set_verify_mode set_ca_store set_custom_certs set_client_credentials end def set_verify_mode if config[:ssl_verify_mode] == :verify_none http_client.verify_mode = OpenSSL::SSL::VERIFY_NONE elsif config[:ssl_verify_mode] == :verify_peer http_client.verify_mode = OpenSSL::SSL::VERIFY_PEER end end def set_ca_store if config[:ssl_ca_path] unless ::File.exist?(config[:ssl_ca_path]) raise Chef::Exceptions::ConfigurationError, "The configured ssl_ca_path #{config[:ssl_ca_path]} does not exist" end http_client.ca_path = config[:ssl_ca_path] elsif config[:ssl_ca_file] unless ::File.exist?(config[:ssl_ca_file]) raise Chef::Exceptions::ConfigurationError, "The configured ssl_ca_file #{config[:ssl_ca_file]} does not exist" end http_client.ca_file = config[:ssl_ca_file] end end def set_custom_certs unless http_client.cert_store http_client.cert_store = OpenSSL::X509::Store.new http_client.cert_store.set_default_paths end if config.trusted_certs_dir certs = Dir.glob(File.join(config.trusted_certs_dir, "*.{crt,pem}")) certs.each do |cert_file| cert = OpenSSL::X509::Certificate.new(File.read(cert_file)) add_trusted_cert(cert) end end end def set_client_credentials if (config[:ssl_client_cert] || config[:ssl_client_key]) unless (config[:ssl_client_cert] && config[:ssl_client_key]) raise Chef::Exceptions::ConfigurationError, "You must configure ssl_client_cert and ssl_client_key together" end unless ::File.exists?(config[:ssl_client_cert]) raise Chef::Exceptions::ConfigurationError, "The configured ssl_client_cert #{config[:ssl_client_cert]} does not exist" end unless ::File.exists?(config[:ssl_client_key]) raise Chef::Exceptions::ConfigurationError, "The configured ssl_client_key #{config[:ssl_client_key]} does not exist" end http_client.cert = OpenSSL::X509::Certificate.new(::File.read(config[:ssl_client_cert])) http_client.key = OpenSSL::PKey::RSA.new(::File.read(config[:ssl_client_key])) end end def config Chef::Config end private def add_trusted_cert(cert) http_client.cert_store.add_cert(cert) rescue OpenSSL::X509::StoreError => e raise e unless e.message == 'cert already in hash table' end end class APISSLPolicy < DefaultSSLPolicy def set_verify_mode if config[:ssl_verify_mode] == :verify_peer or config[:verify_api_cert] http_client.verify_mode = OpenSSL::SSL::VERIFY_PEER elsif config[:ssl_verify_mode] == :verify_none http_client.verify_mode = OpenSSL::SSL::VERIFY_NONE end end end end end chef-11.8.2/lib/chef/http/cookie_jar.rb0000644000004100000410000000201112254362222017616 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Thom May () # Author:: Nuo Yan () # Author:: Christopher Brown () # Author:: Christopher Walters () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2009, 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'singleton' class Chef class HTTP class CookieJar < Hash include Singleton end end end chef-11.8.2/lib/chef/http/authenticator.rb0000644000004100000410000000571412254362222020400 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/http/auth_credentials' require 'chef/exceptions' require 'openssl' class Chef class HTTP class Authenticator attr_reader :signing_key_filename attr_reader :raw_key attr_reader :attr_names attr_reader :auth_credentials attr_accessor :sign_request def initialize(opts={}) @raw_key = nil @sign_request = true @signing_key_filename = opts[:signing_key_filename] @key = load_signing_key(opts[:signing_key_filename], opts[:raw_key]) @auth_credentials = AuthCredentials.new(opts[:client_name], @key) end def handle_request(method, url, headers={}, data=false) headers.merge!(authentication_headers(method, url, data)) if sign_requests? [method, url, headers, data] end def handle_response(http_response, rest_request, return_value) [http_response, rest_request, return_value] end def stream_response_handler(response) nil end def sign_requests? auth_credentials.sign_requests? && @sign_request end def client_name @auth_credentials.client_name end def load_signing_key(key_file, raw_key = nil) if (!!key_file) @raw_key = IO.read(key_file).strip elsif (!!raw_key) @raw_key = raw_key.strip else return nil end @key = OpenSSL::PKey::RSA.new(@raw_key) rescue SystemCallError, IOError => e Chef::Log.warn "Failed to read the private key #{key_file}: #{e.inspect}" raise Chef::Exceptions::PrivateKeyMissing, "I cannot read #{key_file}, which you told me to use to sign requests!" rescue OpenSSL::PKey::RSAError msg = "The file #{key_file} or :raw_key option does not contain a correctly formatted private key.\n" msg << "The key file should begin with '-----BEGIN RSA PRIVATE KEY-----' and end with '-----END RSA PRIVATE KEY-----'" raise Chef::Exceptions::InvalidPrivateKey, msg end def authentication_headers(method, url, json_body=nil) request_params = {:http_method => method, :path => url.path, :body => json_body, :host => "#{url.host}:#{url.port}"} request_params[:body] ||= "" auth_credentials.signature_headers(request_params) end end end end chef-11.8.2/lib/chef/http/decompressor.rb0000644000004100000410000001027712254362222020233 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'zlib' require 'chef/http/http_request' class Chef class HTTP # Middleware-esque class for handling compression in HTTP responses. class Decompressor class NoopInflater def inflate(chunk) chunk end alias :handle_chunk :inflate end class GzipInflater < Zlib::Inflate def initialize super(Zlib::MAX_WBITS + 16) end alias :handle_chunk :inflate end class DeflateInflater < Zlib::Inflate def initialize super end alias :handle_chunk :inflate end CONTENT_ENCODING = "content-encoding".freeze GZIP = "gzip".freeze DEFLATE = "deflate".freeze IDENTITY = "identity".freeze def initialize(opts={}) @disable_gzip = false handle_options(opts) end def handle_request(method, url, headers={}, data=false) headers[HTTPRequest::ACCEPT_ENCODING] = HTTPRequest::ENCODING_GZIP_DEFLATE unless gzip_disabled? [method, url, headers, data] end def handle_response(http_response, rest_request, return_value) # temporary hack, skip processing if return_value is false # needed to keep conditional get stuff working correctly. return [http_response, rest_request, return_value] if return_value == false response_body = decompress_body(http_response) http_response.body.replace(response_body) if http_response.body.respond_to?(:replace) [http_response, rest_request, return_value] end def decompress_body(response) if gzip_disabled? || response.body.nil? response.body else case response[CONTENT_ENCODING] when GZIP Chef::Log.debug "decompressing gzip response" Zlib::Inflate.new(Zlib::MAX_WBITS + 16).inflate(response.body) when DEFLATE Chef::Log.debug "decompressing deflate response" Zlib::Inflate.inflate(response.body) else response.body end end end # This isn't used when this class is used as middleware; it returns an # object you can use to unzip/inflate a streaming response. def stream_response_handler(response) if gzip_disabled? NoopInflater.new else case response[CONTENT_ENCODING] when GZIP Chef::Log.debug "decompressing gzip stream" GzipInflater.new when DEFLATE Chef::Log.debug "decompressing inflate stream" DeflateInflater.new else NoopInflater.new end end end # gzip is disabled using the disable_gzip => true option in the # constructor. When gzip is disabled, no 'Accept-Encoding' header will be # set, and the response will not be decompressed, no matter what the # Content-Encoding header of the response is. The intended use case for # this is to work around situations where you request +file.tar.gz+, but # the server responds with a content type of tar and a content encoding of # gzip, tricking the client into decompressing the response so you end up # with a tar archive (no gzip) named file.tar.gz def gzip_disabled? @disable_gzip end private def handle_options(opts) opts.each do |name, value| case name.to_s when 'disable_gzip' @disable_gzip = value end end end end end end chef-11.8.2/lib/chef/http/json_input.rb0000644000004100000410000000314212254362222017707 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Author:: John Keiser () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/json_compat' class Chef class HTTP # Middleware that takes json input and turns it into raw text class JSONInput def initialize(opts={}) end def handle_request(method, url, headers={}, data=false) if data headers["Content-Type"] = 'application/json' data = Chef::JSONCompat.to_json(data) # Force encoding to binary to fix SSL related EOFErrors # cf. http://tickets.opscode.com/browse/CHEF-2363 # http://redmine.ruby-lang.org/issues/5233 data.force_encoding(Encoding::BINARY) if data.respond_to?(:force_encoding) end [method, url, headers, data] end def handle_response(http_response, rest_request, return_value) [http_response, rest_request, return_value] end def stream_response_handler(response) nil end end end end chef-11.8.2/lib/chef/handler/0000755000004100000410000000000012254362222015630 5ustar www-datawww-datachef-11.8.2/lib/chef/handler/error_report.rb0000644000004100000410000000204512254362222020702 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/handler' require 'chef/resource/directory' class Chef class Handler class ErrorReport < ::Chef::Handler def report Chef::FileCache.store("failed-run-data.json", Chef::JSONCompat.to_json_pretty(data), 0640) Chef::Log.fatal("Saving node information to #{Chef::FileCache.load("failed-run-data.json", false)}") end end end end chef-11.8.2/lib/chef/handler/json_file.rb0000644000004100000410000000351612254362222020132 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/handler' require 'chef/resource/directory' class Chef class Handler class JsonFile < ::Chef::Handler attr_reader :config def initialize(config={}) @config = config @config[:path] ||= "/var/chef/reports" @config end def report if exception Chef::Log.error("Creating JSON exception report") else Chef::Log.info("Creating JSON run report") end build_report_dir savetime = Time.now.strftime("%Y%m%d%H%M%S") File.open(File.join(config[:path], "chef-run-report-#{savetime}.json"), "w") do |file| #ensure start time and end time are output in the json properly in the event activesupport happens to be on the system run_data = data run_data[:start_time] = run_data[:start_time].to_s run_data[:end_time] = run_data[:end_time].to_s file.puts Chef::JSONCompat.to_json_pretty(run_data) end end def build_report_dir unless File.exists?(config[:path]) FileUtils.mkdir_p(config[:path]) File.chmod(00700, config[:path]) end end end end end chef-11.8.2/lib/chef/util/0000755000004100000410000000000012254362222015170 5ustar www-datawww-datachef-11.8.2/lib/chef/util/diff.rb0000644000004100000410000001557012254362222016435 0ustar www-datawww-data# Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # # Some portions of this file are derived from material in the diff-lcs # project licensed under the terms of the MIT license, provided below. # # Copyright:: Copyright (c) 2004-2013 Austin Ziegler # License:: MIT # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of this Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OF OTHER DEALINGS IN THE # SOFTWARE. require 'diff/lcs' require 'diff/lcs/hunk' class Chef class Util class Diff # @todo: to_a, to_s, to_json, inspect defs, accessors for @diff and @error # @todo: move coercion to UTF-8 into to_json # @todo: replace shellout to diff -u with diff-lcs gem def for_output # formatted output to a terminal uses arrays of strings and returns error strings @diff.nil? ? [ @error ] : @diff end def for_reporting # caller needs to ensure that new files aren't posted to resource reporting return nil if @diff.nil? @diff.join("\\n") end def use_tempfile_if_missing(file) tempfile = nil unless File.exists?(file) Chef::Log.debug("file #{file} does not exist to diff against, using empty tempfile") tempfile = Tempfile.new("chef-diff") file = tempfile.path end yield file unless tempfile.nil? tempfile.close tempfile.unlink end end def diff(old_file, new_file) use_tempfile_if_missing(old_file) do |old_file| use_tempfile_if_missing(new_file) do |new_file| @error = do_diff(old_file, new_file) end end end # produces a unified-output-format diff with 3 lines of context # ChefFS uses udiff() directly def udiff(old_file, new_file) diff_str = "" file_length_difference = 0 old_data = IO.readlines(old_file).map { |e| e.chomp } new_data = IO.readlines(new_file).map { |e| e.chomp } diff_data = ::Diff::LCS.diff(old_data, new_data) return diff_str if old_data.empty? && new_data.empty? return "No differences encountered\n" if diff_data.empty? # write diff header (standard unified format) ft = File.stat(old_file).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S.%N %z') diff_str << "--- #{old_file}\t#{ft}\n" ft = File.stat(new_file).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S.%N %z') diff_str << "+++ #{new_file}\t#{ft}\n" # loop over diff hunks. if a hunk overlaps with the last hunk, # join them. otherwise, print out the old one. old_hunk = hunk = nil diff_data.each do |piece| begin hunk = ::Diff::LCS::Hunk.new(old_data, new_data, piece, 3, file_length_difference) file_length_difference = hunk.file_length_difference next unless old_hunk next if hunk.merge(old_hunk) diff_str << old_hunk.diff(:unified) << "\n" ensure old_hunk = hunk end end diff_str << old_hunk.diff(:unified) << "\n" return diff_str end private def do_diff(old_file, new_file) if Chef::Config[:diff_disabled] return "(diff output suppressed by config)" end diff_filesize_threshold = Chef::Config[:diff_filesize_threshold] diff_output_threshold = Chef::Config[:diff_output_threshold] if ::File.size(old_file) > diff_filesize_threshold || ::File.size(new_file) > diff_filesize_threshold return "(file sizes exceed #{diff_filesize_threshold} bytes, diff output suppressed)" end # MacOSX(BSD?) diff will *sometimes* happily spit out nasty binary diffs return "(current file is binary, diff output suppressed)" if is_binary?(old_file) return "(new content is binary, diff output suppressed)" if is_binary?(new_file) begin Chef::Log.debug("running: diff -u #{old_file} #{new_file}") diff_str = udiff(old_file, new_file) rescue Exception => e # Should *not* receive this, but in some circumstances it seems that # an exception can be thrown even using shell_out instead of shell_out! return "Could not determine diff. Error: #{e.message}" end if !diff_str.empty? && diff_str != "No differences encountered\n" if diff_str.length > diff_output_threshold return "(long diff of over #{diff_output_threshold} characters, diff output suppressed)" else diff_str = encode_diff_for_json(diff_str) @diff = diff_str.split("\n") return "(diff available)" end else return "(no diff)" end end def is_binary?(path) File.open(path) do |file| # XXX: this slurps into RAM, but we should have already checked our diff has a reasonable size buff = file.read buff = "" if buff.nil? begin return buff !~ /\A[\s[:print:]]*\z/m rescue ArgumentError => e return true if e.message =~ /invalid byte sequence/ raise end end end def encode_diff_for_json(diff_str) if Object.const_defined? :Encoding diff_str.encode!('UTF-8', :invalid => :replace, :undef => :replace, :replace => '?') end return diff_str end end end end chef-11.8.2/lib/chef/util/windows/0000755000004100000410000000000012254362222016662 5ustar www-datawww-datachef-11.8.2/lib/chef/util/windows/volume.rb0000644000004100000410000000323112254362222020515 0ustar www-datawww-data# # Author:: Doug MacEachern () # Copyright:: Copyright (c) 2010 VMware, Inc. # License:: Apache License, Version 2.0 # # 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. # #simple wrapper around Volume APIs. might be possible with WMI, but possibly more complex. require 'chef/util/windows' require 'windows/volume' class Chef::Util::Windows::Volume < Chef::Util::Windows private include Windows::Volume #XXX not defined in the current windows-pr release DeleteVolumeMountPoint = Windows::API.new('DeleteVolumeMountPoint', 'S', 'B') unless defined? DeleteVolumeMountPoint public def initialize(name) name += "\\" unless name =~ /\\$/ #trailing slash required @name = name end def device buffer = 0.chr * 256 if GetVolumeNameForVolumeMountPoint(@name, buffer, buffer.size) return buffer[0,buffer.size].unpack("Z*")[0] else raise ArgumentError, get_last_error end end def delete unless DeleteVolumeMountPoint.call(@name) raise ArgumentError, get_last_error end end def add(args) unless SetVolumeMountPoint(@name, args[:remote]) raise ArgumentError, get_last_error end end end chef-11.8.2/lib/chef/util/windows/net_use.rb0000644000004100000410000000574212254362222020661 0ustar www-datawww-data# # Author:: Doug MacEachern () # Copyright:: Copyright (c) 2010 VMware, Inc. # License:: Apache License, Version 2.0 # # 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. # #the Win32 Volume APIs do not support mapping network drives. not supported by WMI either. #see also: WNetAddConnection2 and WNetAddConnection3 #see also cmd.exe: net use /? require 'chef/util/windows' class Chef::Util::Windows::NetUse < Chef::Util::Windows private USE_NOFORCE = 0 USE_FORCE = 1 USE_LOTS_OF_FORCE = 2 #every windows API should support this flag USE_INFO_2 = [ [:local, nil], [:remote, nil], [:password, nil], [:status, 0], [:asg_type, 0], [:refcount, 0], [:usecount, 0], [:username, nil], [:domainname, nil] ] USE_INFO_2_TEMPLATE = USE_INFO_2.collect { |field| field[1].class == Fixnum ? 'i' : 'L' }.join SIZEOF_USE_INFO_2 = #sizeof(USE_INFO_2) USE_INFO_2.inject(0){|sum,item| sum + (item[1].class == Fixnum ? 4 : PTR_SIZE) } def use_info_2(args) USE_INFO_2.collect { |field| args.include?(field[0]) ? args[field[0]] : field[1] } end def use_info_2_pack(use) use.collect { |v| v.class == Fixnum ? v : str_to_ptr(multi_to_wide(v)) }.pack(USE_INFO_2_TEMPLATE) end def use_info_2_unpack(buffer) use = Hash.new USE_INFO_2.each_with_index do |field,offset| use[field[0]] = field[1].class == Fixnum ? dword_to_i(buffer, offset) : lpwstr_to_s(buffer, offset) end use end public def initialize(localname) @localname = localname @name = multi_to_wide(localname) end def add(args) if args.class == String remote = args args = Hash.new args[:remote] = remote end args[:local] ||= @localname use = use_info_2(args) buffer = use_info_2_pack(use) rc = NetUseAdd.call(nil, 2, buffer, nil) if rc != NERR_Success raise ArgumentError, get_last_error(rc) end end def get_info ptr = 0.chr * PTR_SIZE rc = NetUseGetInfo.call(nil, @name, 2, ptr) if rc != NERR_Success raise ArgumentError, get_last_error(rc) end ptr = ptr.unpack('L')[0] buffer = 0.chr * SIZEOF_USE_INFO_2 memcpy(buffer, ptr, buffer.size) NetApiBufferFree(ptr) use_info_2_unpack(buffer) end def device get_info()[:remote] end #XXX should we use some FORCE here? def delete rc = NetUseDel.call(nil, @name, USE_NOFORCE) if rc != NERR_Success raise ArgumentError, get_last_error(rc) end end end chef-11.8.2/lib/chef/util/windows/net_user.rb0000644000004100000410000001361112254362222021035 0ustar www-datawww-data# # Author:: Doug MacEachern () # Copyright:: Copyright (c) 2010 VMware, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/util/windows' #wrapper around a subset of the NetUser* APIs. #nothing Chef specific, but not complete enough to be its own gem, so util for now. class Chef::Util::Windows::NetUser < Chef::Util::Windows private LogonUser = Windows::API.new('LogonUser', 'SSSLLP', 'I', 'advapi32') DOMAIN_GROUP_RID_USERS = 0x00000201 UF_SCRIPT = 0x000001 UF_ACCOUNTDISABLE = 0x000002 UF_PASSWD_CANT_CHANGE = 0x000040 UF_NORMAL_ACCOUNT = 0x000200 UF_DONT_EXPIRE_PASSWD = 0x010000 #[:symbol_name, default_val] #default_val duals as field type #array index duals as structure offset #OC-8391 #Changing [:password, nil], to [:password, ""], #if :password is set to nil, windows user creation api ignores the password policy applied #thus initializing it with empty string value. USER_INFO_3 = [ [:name, nil], [:password, ""], [:password_age, 0], [:priv, 0], #"The NetUserAdd and NetUserSetInfo functions ignore this member" [:home_dir, nil], [:comment, nil], [:flags, UF_SCRIPT|UF_DONT_EXPIRE_PASSWD|UF_NORMAL_ACCOUNT], [:script_path, nil], [:auth_flags, 0], [:full_name, nil], [:user_comment, nil], [:parms, nil], [:workstations, nil], [:last_logon, 0], [:last_logoff, 0], [:acct_expires, -1], [:max_storage, -1], [:units_per_week, 0], [:logon_hours, nil], [:bad_pw_count, 0], [:num_logons, 0], [:logon_server, nil], [:country_code, 0], [:code_page, 0], [:user_id, 0], [:primary_group_id, DOMAIN_GROUP_RID_USERS], [:profile, nil], [:home_dir_drive, nil], [:password_expired, 0] ] USER_INFO_3_TEMPLATE = USER_INFO_3.collect { |field| field[1].class == Fixnum ? 'i' : 'L' }.join SIZEOF_USER_INFO_3 = #sizeof(USER_INFO_3) USER_INFO_3.inject(0){|sum,item| sum + (item[1].class == Fixnum ? 4 : PTR_SIZE) } def user_info_3(args) USER_INFO_3.collect { |field| args.include?(field[0]) ? args[field[0]] : field[1] } end def user_info_3_pack(user) user.collect { |v| v.class == Fixnum ? v : str_to_ptr(multi_to_wide(v)) }.pack(USER_INFO_3_TEMPLATE) end def user_info_3_unpack(buffer) user = Hash.new USER_INFO_3.each_with_index do |field,offset| user[field[0]] = field[1].class == Fixnum ? dword_to_i(buffer, offset) : lpwstr_to_s(buffer, offset) end user end def set_info(args) user = user_info_3(args) buffer = user_info_3_pack(user) rc = NetUserSetInfo.call(nil, @name, 3, buffer, nil) if rc != NERR_Success raise ArgumentError, get_last_error(rc) end end public def initialize(username) @username = username @name = multi_to_wide(username) end LOGON32_PROVIDER_DEFAULT = 0 LOGON32_LOGON_NETWORK = 3 #XXX for an extra painful alternative, see: http://support.microsoft.com/kb/180548 def validate_credentials(passwd) token = 0.chr * PTR_SIZE res = LogonUser.call(@username, nil, passwd, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, token) if res == 0 return false end ::Windows::Handle::CloseHandle.call(token.unpack('L')[0]) return true end def get_info ptr = 0.chr * PTR_SIZE rc = NetUserGetInfo.call(nil, @name, 3, ptr) if rc != NERR_Success raise ArgumentError, get_last_error(rc) end ptr = ptr.unpack('L')[0] buffer = 0.chr * SIZEOF_USER_INFO_3 memcpy(buffer, ptr, buffer.size) NetApiBufferFree(ptr) user_info_3_unpack(buffer) end def add(args) user = user_info_3(args) buffer = user_info_3_pack(user) rc = NetUserAdd.call(nil, 3, buffer, rc) if rc != NERR_Success raise ArgumentError, get_last_error(rc) end #usri3_primary_group_id: #"When you call the NetUserAdd function, this member must be DOMAIN_GROUP_RID_USERS" NetLocalGroupAddMembers(nil, multi_to_wide("Users"), 3, buffer[0,PTR_SIZE], 1) end def user_modify(&proc) user = get_info user[:last_logon] = user[:units_per_week] = 0 #ignored as per USER_INFO_3 doc user[:logon_hours] = nil #PBYTE field; \0 == no changes proc.call(user) set_info(user) end def update(args) user_modify do |user| args.each do |key,val| user[key] = val end end end def delete rc = NetUserDel.call(nil, @name) if rc != NERR_Success raise ArgumentError, get_last_error(rc) end end def disable_account user_modify do |user| user[:flags] |= UF_ACCOUNTDISABLE #This does not set the password to nil. It (for some reason) means to ignore updating the field. #See similar behavior for the logon_hours field documented at #http://msdn.microsoft.com/en-us/library/windows/desktop/aa371338%28v=vs.85%29.aspx user[:password] = nil end end def enable_account user_modify do |user| user[:flags] &= ~UF_ACCOUNTDISABLE #This does not set the password to nil. It (for some reason) means to ignore updating the field. #See similar behavior for the logon_hours field documented at #http://msdn.microsoft.com/en-us/library/windows/desktop/aa371338%28v=vs.85%29.aspx user[:password] = nil end end def check_enabled (get_info()[:flags] & UF_ACCOUNTDISABLE) != 0 end end chef-11.8.2/lib/chef/util/windows/net_group.rb0000644000004100000410000000552612254362222021221 0ustar www-datawww-data# # Author:: Doug MacEachern () # Copyright:: Copyright (c) 2010 VMware, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/util/windows' #wrapper around a subset of the NetGroup* APIs. #nothing Chef specific, but not complete enough to be its own gem, so util for now. class Chef::Util::Windows::NetGroup < Chef::Util::Windows private def pack_str(s) [str_to_ptr(s)].pack('L') end def modify_members(members, func) buffer = 0.chr * (members.size * PTR_SIZE) members.each_with_index do |member,offset| buffer[offset*PTR_SIZE,PTR_SIZE] = pack_str(multi_to_wide(member)) end rc = func.call(nil, @name, 3, buffer, members.size) if rc != NERR_Success raise ArgumentError, get_last_error(rc) end end public def initialize(groupname) @name = multi_to_wide(groupname) end def local_get_members group_members = [] handle = 0.chr * PTR_SIZE rc = ERROR_MORE_DATA while rc == ERROR_MORE_DATA ptr = 0.chr * PTR_SIZE nread = 0.chr * PTR_SIZE total = 0.chr * PTR_SIZE rc = NetLocalGroupGetMembers.call(nil, @name, 1, ptr, -1, nread, total, handle) if (rc == NERR_Success) || (rc == ERROR_MORE_DATA) ptr = ptr.unpack('L')[0] nread = nread.unpack('i')[0] members = 0.chr * (nread * (PTR_SIZE * 3)) #nread * sizeof(LOCALGROUP_MEMBERS_INFO_1) memcpy(members, ptr, members.size) #3 pointer fields in LOCALGROUP_MEMBERS_INFO_1, offset 2*PTR_SIZE is lgrmi1_name nread.times do |i| offset = (i * 3) + 2 member = lpwstr_to_s(members, offset) group_members << member end NetApiBufferFree(ptr) else raise ArgumentError, get_last_error(rc) end end group_members end def local_add rc = NetLocalGroupAdd.call(nil, 0, pack_str(@name), nil) if rc != NERR_Success raise ArgumentError, get_last_error(rc) end end def local_set_members(members) modify_members(members, NetLocalGroupSetMembers) end def local_add_members(members) modify_members(members, NetLocalGroupAddMembers) end def local_delete rc = NetLocalGroupDel.call(nil, @name) if rc != NERR_Success raise ArgumentError, get_last_error(rc) end end end chef-11.8.2/lib/chef/util/selinux.rb0000644000004100000410000000607712254362222017216 0ustar www-datawww-data# # Author:: Sean O'Meara # Author:: Kevin Keane # Author:: Lamont Granquist () # # Copyright:: Copyright (c) 2011 Opscode, Inc. # Copyright:: Copyright (c) 2013, North County Tech Center, LLC # # License:: Apache License, Version 2.0 # # 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. require 'chef/mixin/shell_out' class Chef class Util # # IMPORTANT: We assume that selinux utilities are installed on an # selinux enabled server. Provisioning an selinux enabled server # without selinux utilities is not supported. # module Selinux include Chef::Mixin::ShellOut # We want to initialize below variables once during a # chef-client run therefore they are class variables. @@selinux_enabled = nil @@restorecon_path = nil @@selinuxenabled_path = nil def selinux_enabled? @@selinux_enabled = check_selinux_enabled? if @@selinux_enabled.nil? @@selinux_enabled end def restore_security_context(file_path, recursive = false) if restorecon_path restorecon_command = recursive ? "#{restorecon_path} -R -r" : "#{restorecon_path} -R" restorecon_command += " #{file_path}" Chef::Log.debug("Restoring selinux security content with #{restorecon_command}") shell_out!(restorecon_command) else Chef::Log.warn "Can not find 'restorecon' on the system. Skipping selinux security context restore." end end private def restorecon_path @@restorecon_path = which("restorecon") if @@restorecon_path.nil? @@restorecon_path end def selinuxenabled_path @@selinuxenabled_path = which("selinuxenabled") if @@selinuxenabled_path.nil? @@selinuxenabled_path end def which(cmd) paths = ENV['PATH'].split(File::PATH_SEPARATOR) + [ '/bin', '/usr/bin', '/sbin', '/usr/sbin' ] paths.each do |path| filename = File.join(path, cmd) return filename if File.executable?(filename) end false end def check_selinux_enabled? if selinuxenabled_path cmd = shell_out!(selinuxenabled_path, :returns => [0,1]) case cmd.exitstatus when 1 return false when 0 return true else raise RuntimeError, "Unknown exit code from command #{selinuxenabled_path}: #{cmd.exitstatus}" end else # We assume selinux is not enabled if selinux utils are not # installed. return false end end end end end chef-11.8.2/lib/chef/util/backup.rb0000644000004100000410000000541612254362222016770 0ustar www-datawww-data# # Author:: Lamont Granquist () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Util class Backup attr_reader :new_resource attr_accessor :path def initialize(new_resource, path = nil) @new_resource = new_resource @path = path.nil? ? new_resource.path : path end def backup! if @new_resource.backup != false && @new_resource.backup > 0 && ::File.exist?(path) do_backup # Clean up after the number of backups slice_number = @new_resource.backup backup_files = sorted_backup_files if backup_files.length >= @new_resource.backup remainder = backup_files.slice(slice_number..-1) remainder.each do |backup_to_delete| delete_backup(backup_to_delete) end end end end private def backup_filename @backup_filename ||= begin time = Time.now nanoseconds = sprintf("%6f", time.to_f).split('.')[1] savetime = time.strftime("%Y%m%d%H%M%S.#{nanoseconds}") backup_filename = "#{path}.chef-#{savetime}" backup_filename = backup_filename.sub(/^([A-Za-z]:)/, "") #strip drive letter on Windows end end def prefix # if :file_backup_path is nil, we fallback to the old behavior of # keeping the backup in the same directory. We also need to to_s it # so we don't get a type error around implicit to_str conversions. @prefix ||= Chef::Config[:file_backup_path].to_s end def backup_path @backup_path ||= ::File.join(prefix, backup_filename) end def do_backup FileUtils.mkdir_p(::File.dirname(backup_path)) if Chef::Config[:file_backup_path] FileUtils.cp(path, backup_path, :preserve => true) Chef::Log.info("#{@new_resource} backed up to #{backup_path}") end def delete_backup(backup_file) FileUtils.rm(backup_file) Chef::Log.info("#{@new_resource} removed backup at #{backup_file}") end def sorted_backup_files Dir[::File.join(prefix, ".#{path}.chef-*")].sort { |a,b| b <=> a } end end end end chef-11.8.2/lib/chef/util/file_edit.rb0000644000004100000410000001060112254362222017437 0ustar www-datawww-data# # Author:: Nuo Yan () # Copyright:: Copyright (c) 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'fileutils' require 'tempfile' class Chef class Util class FileEdit private attr_accessor :original_pathname, :contents, :file_edited public def initialize(filepath) @original_pathname = filepath @file_edited = false raise ArgumentError, "File doesn't exist" unless File.exist? @original_pathname @contents = File.new(@original_pathname).readlines end #search the file line by line and match each line with the given regex #if matched, replace the whole line with newline. def search_file_replace_line(regex, newline) search_match(regex, newline, 'r', 1) end #search the file line by line and match each line with the given regex #if matched, replace the match (all occurances) with the replace parameter def search_file_replace(regex, replace) search_match(regex, replace, 'r', 2) end #search the file line by line and match each line with the given regex #if matched, delete the line def search_file_delete_line(regex) search_match(regex, " ", 'd', 1) end #search the file line by line and match each line with the given regex #if matched, delete the match (all occurances) from the line def search_file_delete(regex) search_match(regex, " ", 'd', 2) end #search the file line by line and match each line with the given regex #if matched, insert newline after each matching line def insert_line_after_match(regex, newline) search_match(regex, newline, 'i', 1) end #search the file line by line and match each line with the given regex #if not matched, insert newline at the end of the file def insert_line_if_no_match(regex, newline) search_match(regex, newline, 'i', 2) end #Make a copy of old_file and write new file out (only if file changed) def write_file # file_edited is false when there was no match in the whole file and thus no contents have changed. if file_edited backup_pathname = original_pathname + ".old" FileUtils.cp(original_pathname, backup_pathname, :preserve => true) File.open(original_pathname, "w") do |newfile| contents.each do |line| newfile.puts(line) end newfile.flush end end self.file_edited = false end private #helper method to do the match, replace, delete, and insert operations #command is the switch of delete, replace, and insert ('d', 'r', 'i') #method is to control operation on whole line or only the match (1 for line, 2 for match) def search_match(regex, replace, command, method) #convert regex to a Regexp object (if not already is one) and store it in exp. exp = Regexp.new(regex) #loop through contents and do the appropriate operation depending on 'command' and 'method' new_contents = [] contents.each do |line| if line.match(exp) self.file_edited = true case when command == 'r' new_contents << ((method == 1) ? replace : line.gsub!(exp, replace)) when command == 'd' if method == 2 new_contents << line.gsub!(exp, "") end when command == 'i' new_contents << line new_contents << replace unless method == 2 end else new_contents << line end end if command == 'i' && method == 2 && ! file_edited new_contents << replace self.file_edited = true end self.contents = new_contents end end end end chef-11.8.2/lib/chef/util/windows.rb0000644000004100000410000000317412254362222017214 0ustar www-datawww-data# # Author:: Doug MacEachern () # Copyright:: Copyright (c) 2010 VMware, Inc. # License:: Apache License, Version 2.0 # # 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. # #requires: gem install windows-pr require 'windows/api' require 'windows/error' require 'windows/handle' require 'windows/unicode' require 'windows/msvcrt/buffer' require 'windows/msvcrt/string' require 'windows/network/management' class Chef class Util class Windows protected include ::Windows::Error include ::Windows::Unicode include ::Windows::MSVCRT::Buffer include ::Windows::MSVCRT::String include ::Windows::Network::Management PTR_SIZE = 4 #XXX 64-bit def lpwstr_to_s(buffer, offset) str = 0.chr * (256 * 2) #XXX unhardcode this length (*2 for WCHAR) wcscpy str, buffer[offset*PTR_SIZE,PTR_SIZE].unpack('L')[0] wide_to_multi str end def dword_to_i(buffer, offset) buffer[offset*PTR_SIZE,PTR_SIZE].unpack('i')[0] || 0 end #return pointer for use with pack('L') def str_to_ptr(v) [v].pack('p*').unpack('L')[0] end end end end chef-11.8.2/lib/chef/sandbox.rb0000644000004100000410000000162412254362222016201 0ustar www-datawww-dataclass Chef class Sandbox # I DO NOTHING!! # So, the reason we have a completely empty class here is so that # Chef 11 clients do not choke when interacting with Chef 10 # servers. The original Chef::Sandbox class (that actually did # things) has been removed since its functionality is no longer # needed for Chef 11. However, since we still use the JSON gem # and make use of its "auto-inflation" of classes (driven by the # contents of the 'json_class' key in all of our JSON), any # sandbox responses from a Chef 10 server to a Chef 11 client # would cause knife to crash. The JSON gem would attempt to # auto-inflate based on a "json_class": "Chef::Sandbox" hash # entry, but would not be able to find a Chef::Sandbox class! # # This is a workaround until such time as we can completely remove # the reliance on the "json_class" field. end end chef-11.8.2/lib/chef/file_access_control.rb0000644000004100000410000000451512254362222020545 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008, 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/log' class Chef # == Chef::FileAccessControl # FileAccessControl objects set the owner, group and mode of +file+ to # the values specified by a value object, usually a Chef::Resource. class FileAccessControl if RUBY_PLATFORM =~ /mswin|mingw|windows/ require 'chef/file_access_control/windows' include FileAccessControl::Windows else require 'chef/file_access_control/unix' include FileAccessControl::Unix end attr_reader :current_resource attr_reader :resource attr_reader :provider attr_reader :file # FileAccessControl objects set the owner, group and mode of +file+ to # the values specified by +resource+. +file+ is completely independent # of any file or path attribute on +resource+, so it is possible to set # access control settings on a tempfile (for example). # === Arguments: # resource: probably a Chef::Resource::File object (or subclass), but # this is not required. Must respond to +owner+, +group+, # and +mode+ # file: The file whose access control settings you wish to modify, # given as a String. # # TODO requiring current_resource will break cookbook_file template_file def initialize(current_resource, new_resource, provider) @current_resource, @resource, @provider = current_resource, new_resource, provider @file = @current_resource.path @modified = false end def modified? @modified end private def modified @modified = true end def log_string @resource || @file end end end chef-11.8.2/lib/chef/file_cache.rb0000644000004100000410000001431412254362222016605 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'chef/mixin/params_validate' require 'chef/mixin/create_path' require 'chef/exceptions' require 'chef/json_compat' require 'fileutils' class Chef class FileCache class << self include Chef::Mixin::ParamsValidate include Chef::Mixin::CreatePath # Write a file to the File Cache. # # === Parameters # path:: The path to the file you want to put in the cache - should # be relative to file_cache_path # contents:: A string with the contents you want written to the file # perm:: Sets file permission bits. Permission bits are platform # dependent; on Unix systems, see open(2) for details. # # === Returns # true def store(path, contents, perm=0640) validate( { :path => path, :contents => contents }, { :path => { :kind_of => String }, :contents => { :kind_of => String }, } ) file_path_array = File.split(path) file_name = file_path_array.pop cache_path = create_cache_path(File.join(file_path_array)) File.open(File.join(cache_path, file_name), "w", perm) do |io| io.print(contents) end true end # Move a file into the cache. Useful with the REST raw file output. # # === Parameters # file:: The path to the file you want in the cache # path:: The relative name you want the new file to use def move_to(file, path) validate( { :file => file, :path => path }, { :file => { :kind_of => String }, :path => { :kind_of => String }, } ) file_path_array = File.split(path) file_name = file_path_array.pop if File.exists?(file) && File.writable?(file) FileUtils.mv( file, File.join(create_cache_path(File.join(file_path_array), true), file_name) ) else raise RuntimeError, "Cannot move #{file} to #{path}!" end end # Read a file from the File Cache # # === Parameters # path:: The path to the file you want to load - should # be relative to file_cache_path # read:: Whether to return the file contents, or the path. # Defaults to true. # # === Returns # String:: A string with the file contents, or the path to the file. # # === Raises # Chef::Exceptions::FileNotFound:: If it cannot find the file in the cache def load(path, read=true) validate( { :path => path }, { :path => { :kind_of => String } } ) cache_path = create_cache_path(path, false) raise Chef::Exceptions::FileNotFound, "Cannot find #{cache_path} for #{path}!" unless File.exists?(cache_path) if read File.read(cache_path) else cache_path end end # Delete a file from the File Cache # # === Parameters # path:: The path to the file you want to delete - should # be relative to file_cache_path # # === Returns # true def delete(path) validate( { :path => path }, { :path => { :kind_of => String }, } ) cache_path = create_cache_path(path, false) if File.exists?(cache_path) File.unlink(cache_path) end true end # List all the files in the Cache # # === Returns # Array:: An array of files in the cache, suitable for use with load, delete and store def list find("**#{File::Separator}*") end ## # Find files in the cache by +glob_pattern+ # === Returns # [String] - An array of file cache keys matching the glob def find(glob_pattern) keys = Array.new Dir[File.join(file_cache_path, glob_pattern)].each do |f| if File.file?(f) keys << f[/^#{Regexp.escape(Dir[file_cache_path].first) + File::Separator}(.+)/, 1] end end keys end # Whether or not this file exists in the Cache # # === Parameters # path:: The path to the file you want to check - is relative # to file_cache_path # # === Returns # True:: If the file exists # False:: If it does not def has_key?(path) validate( { :path => path }, { :path => { :kind_of => String }, } ) full_path = create_cache_path(path, false) if File.exists?(full_path) true else false end end # Create a full path to a given file in the cache. By default, # also creates the path if it does not exist. # # === Parameters # path:: The path to create, relative to file_cache_path # create_if_missing:: True by default - whether to create the path if it does not exist # # === Returns # String:: The fully expanded path def create_cache_path(path, create_if_missing=true) cache_dir = File.expand_path(File.join(file_cache_path, path)) if create_if_missing create_path(cache_dir) else cache_dir end end private def file_cache_path Chef::Config[:file_cache_path] end end end end chef-11.8.2/lib/chef/run_list.rb0000644000004100000410000001105312254362222016377 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Nuo Yan () # Author:: Tim Hinderliter () # Author:: Christopher Walters () # Author:: Seth Falcon () # Copyright:: Copyright (c) 2008-2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'chef/run_list/run_list_item' require 'chef/run_list/run_list_expansion' require 'chef/run_list/versioned_recipe_list' require 'chef/mixin/params_validate' class Chef class RunList include Enumerable include Chef::Mixin::ParamsValidate # @run_list_items is an array of RunListItems that describe the items to # execute in order. RunListItems can load from and convert to the string # forms users set on roles and nodes. # For example: # @run_list_items = ['recipe[foo::bar]', 'role[webserver]'] # Thus, # self.role_names would return ['webserver'] # self.recipe_names would return ['foo::bar'] attr_reader :run_list_items # For backwards compat alias :run_list :run_list_items def initialize(*run_list_items) @run_list_items = run_list_items.map { |i| coerce_to_run_list_item(i) } end def role_names @run_list_items.inject([]){|memo, run_list_item| memo << run_list_item.name if run_list_item.role? ; memo} end alias :roles :role_names def recipe_names @run_list_items.inject([]){|memo, run_list_item| memo << run_list_item.name if run_list_item.recipe? ; memo} end alias :recipes :recipe_names # Add an item of the form "recipe[foo::bar]" or "role[webserver]"; # takes a String or a RunListItem def <<(run_list_item) run_list_item = coerce_to_run_list_item(run_list_item) @run_list_items << run_list_item unless @run_list_items.include?(run_list_item) self end alias :push :<< alias :add :<< def ==(other) if other.kind_of?(Chef::RunList) other.run_list_items == @run_list_items else return false unless other.respond_to?(:size) && (other.size == @run_list_items.size) other_run_list_items = other.dup other_run_list_items.map! { |item| coerce_to_run_list_item(item) } other_run_list_items == @run_list_items end end def to_s @run_list_items.join(", ") end def to_json(*args) to_a.map { |item| item.to_s}.to_json(*args) end def empty? @run_list_items.length == 0 ? true : false end def [](pos) @run_list_items[pos] end def []=(pos, item) @run_list_items[pos] = parse_entry(item) end def each(&block) @run_list_items.each { |i| block.call(i) } end def each_index(&block) @run_list_items.each_index { |i| block.call(i) } end def include?(item) @run_list_items.include?(parse_entry(item)) end def reset!(*args) @run_list_items.clear args.flatten.each do |item| if item.kind_of?(Chef::RunList) item.each { |r| self << r } else self << item end end self end def remove(item) @run_list_items.delete_if{|i| i == item} self end alias :delete :remove # Expands this run_list: recursively expand roles into their included # recipes. # Returns a RunListExpansion object. def expand(environment, data_source='server', expansion_opts={}) expansion = expansion_for_data_source(environment, data_source, expansion_opts) expansion.expand expansion end # Converts a string run list entry to a RunListItem object. def parse_entry(entry) RunListItem.new(entry) end def coerce_to_run_list_item(item) item.kind_of?(RunListItem) ? item : parse_entry(item) end def expansion_for_data_source(environment, data_source, opts={}) case data_source.to_s when 'disk' RunListExpansionFromDisk.new(environment, @run_list_items) when 'server' RunListExpansionFromAPI.new(environment, @run_list_items, opts[:rest]) end end end end chef-11.8.2/lib/chef/applications.rb0000644000004100000410000000024512254362222017227 0ustar www-datawww-datarequire 'chef/application/agent' require 'chef/application/client' require 'chef/application/knife' require 'chef/application/solo' require 'chef/application/apply' chef-11.8.2/lib/chef/nil_argument.rb0000644000004100000410000000005312254362222017222 0ustar www-datawww-dataclass Chef NIL_ARGUMENT = Object.new end chef-11.8.2/lib/chef/api_client/0000755000004100000410000000000012254362222016322 5ustar www-datawww-datachef-11.8.2/lib/chef/api_client/registration.rb0000644000004100000410000001071612254362222021366 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/config' require 'chef/rest' require 'chef/exceptions' class Chef class ApiClient # ==Chef::ApiClient::Registration # Manages the process of creating or updating a Chef::ApiClient on the # server and writing the resulting private key to disk. Registration uses # the validator credentials for its API calls. This allows it to bootstrap # a new client/node identity by borrowing the validator client identity # when creating a new client. class Registration attr_reader :private_key attr_reader :destination attr_reader :name def initialize(name, destination) @name = name @destination = destination @private_key = nil end # Runs the client registration process, including creating the client on # the chef-server and writing its private key to disk. #-- # If client creation fails with a 5xx, it is retried up to 5 times. These # retries are on top of the retries with randomized exponential backoff # built in to Chef::REST. The retries here are a workaround for failures # caused by resource contention in Hosted Chef when creating a very large # number of clients simultaneously, (e.g., spinning up 100s of ec2 nodes # at once). Future improvements to the affected component should make # these retries unnecessary. def run assert_destination_writable! retries = Config[:client_registration_retries] || 5 begin create_or_update rescue Net::HTTPFatalError => e # HTTPFatalError implies 5xx. raise if retries <= 0 retries -= 1 Chef::Log.warn("Failed to register new client, #{retries} tries remaining") Chef::Log.warn("Response: HTTP #{e.response.code} - #{e}") retry end write_key end def assert_destination_writable! if (File.exists?(destination) && !File.writable?(destination)) or !File.writable?(File.dirname(destination)) raise Chef::Exceptions::CannotWritePrivateKey, "I cannot write your private key to #{destination} - check permissions?" end end def write_key ::File.open(destination, file_flags, 0600) do |f| f.print(private_key) end rescue IOError => e raise Chef::Exceptions::CannotWritePrivateKey, "Error writing private key to #{destination}: #{e}" end def create_or_update create rescue Net::HTTPServerException => e # If create fails because the client exists, attempt to update. This # requires admin privileges. raise unless e.response.code == "409" update end def create response = http_api.post("clients", :name => name, :admin => false) @private_key = response["private_key"] response end def update response = http_api.put("clients/#{name}", :name => name, :admin => false, :private_key => true) if response.respond_to?(:private_key) # Chef 11 @private_key = response.private_key else # Chef 10 @private_key = response["private_key"] end response end def http_api @http_api_as_validator ||= Chef::REST.new(Chef::Config[:chef_server_url], Chef::Config[:validation_client_name], Chef::Config[:validation_key]) end def file_flags base_flags = File::CREAT|File::TRUNC|File::RDWR # Windows doesn't have symlinks, so it doesn't have NOFOLLOW base_flags |= File::NOFOLLOW if defined?(File::NOFOLLOW) base_flags end end end end chef-11.8.2/lib/chef/scan_access_control.rb0000644000004100000410000001061712254362222020552 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef # == ScanAccessControl # Reads Access Control Settings on a file and writes them out to a resource # (should be the current_resource), attempting to match the style used by the # new resource, that is, if users are specified with usernames in # new_resource, then the uids from stat will be looked up and usernames will # be added to current_resource. # # === Why? # FileAccessControl objects may operate on a temporary file, in which case we # won't know if the access control settings changed (ex: rendering a template # with both a change in content and ownership). For auditing purposes, we # need to record the current state of a file system entity. #-- # Not yet sure if this is the optimal way to solve the problem. But it's # progress towards the end goal. # # TODO: figure out if all this works with OS X's negative uids # TODO: windows class ScanAccessControl attr_reader :new_resource attr_reader :current_resource def initialize(new_resource, current_resource) @new_resource, @current_resource = new_resource, current_resource end # Modifies @current_resource, setting the current access control state. def set_all! if ::File.exist?(new_resource.path) set_owner set_group set_mode else # leave the values as nil. end end # Set the owner attribute of +current_resource+ to whatever the current # state is. Attempts to match the format given in new_resource: if the # new_resource specifies the owner as a string, the username for the uid # will be looked up and owner will be set to the username, and vice versa. def set_owner @current_resource.owner(current_owner) end def current_owner case new_resource.owner when String, nil lookup_uid when Integer stat.uid else Chef::Log.error("The `owner` parameter of the #@new_resource resource is set to an invalid value (#{new_resource.owner.inspect})") raise ArgumentError, "cannot resolve #{new_resource.owner.inspect} to uid, owner must be a string or integer" end end def lookup_uid unless (pwent = Etc.getpwuid(stat.uid)).nil? pwent.name else stat.uid end rescue ArgumentError stat.uid end # Set the group attribute of +current_resource+ to whatever the current state is. def set_group @current_resource.group(current_group) end def current_group case new_resource.group when String, nil lookup_gid when Integer stat.gid else Chef::Log.error("The `group` parameter of the #@new_resource resource is set to an invalid value (#{new_resource.owner.inspect})") raise ArgumentError, "cannot resolve #{new_resource.group.inspect} to gid, group must be a string or integer" end end def lookup_gid unless (pwent = Etc.getgrgid(stat.gid)).nil? pwent.name else stat.gid end rescue ArgumentError stat.gid end def set_mode @current_resource.mode(current_mode) end def current_mode case new_resource.mode when String, Integer, nil "0#{(stat.mode & 07777).to_s(8)}" else Chef::Log.error("The `mode` parameter of the #@new_resource resource is set to an invalid value (#{new_resource.mode.inspect})") raise ArgumentError, "Invalid value #{new_resource.mode.inspect} for `mode` on resource #@new_resource" end end def stat @stat ||= if @new_resource.instance_of?(Chef::Resource::Link) ::File.lstat(@new_resource.path) else realpath = ::File.realpath(@new_resource.path) ::File.stat(realpath) end end end end chef-11.8.2/lib/chef/run_list/0000755000004100000410000000000012254362222016052 5ustar www-datawww-datachef-11.8.2/lib/chef/run_list/run_list_expansion.rb0000644000004100000410000001352712254362222022332 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Author:: Tim Hinderliter () # Copyright:: Copyright (c) 2010, 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'chef/mash' require 'chef/mixin/deep_merge' require 'chef/role' require 'chef/rest' class Chef class RunList # Abstract Base class for expanding a run list. Subclasses must handle # fetching roles from a data source by defining +fetch_role+ class RunListExpansion attr_reader :run_list_items # A VersionedRecipeList of recipes. Populated only after #expand # is called. attr_reader :recipes attr_reader :default_attrs attr_reader :override_attrs attr_reader :environment attr_reader :missing_roles_with_including_role # The data source passed to the constructor. Not used in this class. # In subclasses, this is a couchdb or Chef::REST object pre-configured # to fetch roles from their correct location. attr_reader :source # Returns a Hash of the form "including_role" => "included_role_or_recipe". # This can be used to show the expanded run list (ordered) graph. # ==== Caveats # * Duplicate roles are not shown. attr_reader :run_list_trace def initialize(environment, run_list_items, source=nil) @environment = environment @missing_roles_with_including_role = Array.new @run_list_items = run_list_items.dup @source = source @default_attrs = Mash.new @override_attrs = Mash.new @recipes = Chef::RunList::VersionedRecipeList.new @applied_roles = {} @run_list_trace = Hash.new {|h, key| h[key] = [] } end # Did we find any errors (expanding roles)? def errors? @missing_roles_with_including_role.length > 0 end alias :invalid? :errors? # Recurses over the run list items, expanding roles. After this, # +recipes+ will contain the fully expanded recipe list def expand # Sure do miss function arity when being recursive expand_run_list_items(@run_list_items) end # Fetches and inflates a role # === Returns # Chef::Role in most cases # false if the role has already been applied # nil if the role does not exist def inflate_role(role_name, included_by) return false if applied_role?(role_name) # Prevent infinite loops applied_role(role_name) fetch_role(role_name, included_by) end def apply_role_attributes(role) @default_attrs = Chef::Mixin::DeepMerge.role_merge(@default_attrs, role.default_attributes) @override_attrs = Chef::Mixin::DeepMerge.role_merge(@override_attrs, role.override_attributes) end def applied_role?(role_name) @applied_roles.has_key?(role_name) end # Returns an array of role names that were expanded; this # includes any roles that were in the original, pre-expansion # run_list as well as roles processed during # expansion. Populated only after #expand is called. def roles @applied_roles.keys end # In subclasses, this method will fetch the role from the data source. def fetch_role(name, included_by) raise NotImplementedError end # When a role is not found, an error message is logged, but no # exception is raised. We do add an entry in the errors collection. # === Returns # nil def role_not_found(name, included_by) Chef::Log.error("Role #{name} (included by '#{included_by}') is in the runlist but does not exist. Skipping expand.") @missing_roles_with_including_role << [name, included_by] nil end def errors @missing_roles_with_including_role.map {|item| item.first } end private # these methods modifies internal state based on arguments, so hide it. def applied_role(role_name) @applied_roles[role_name] = true end def expand_run_list_items(items, included_by="top level") if entry = items.shift @run_list_trace[included_by.to_s] << entry.to_s case entry.type when :recipe recipes.add_recipe(entry.name, entry.version) when :role if role = inflate_role(entry.name, included_by) expand_run_list_items(role.run_list_for(@environment).run_list_items, role) apply_role_attributes(role) end end expand_run_list_items(items, included_by) end end end # Expand a run list from disk. Suitable for chef-solo class RunListExpansionFromDisk < RunListExpansion def fetch_role(name, included_by) Chef::Role.from_disk(name) rescue Chef::Exceptions::RoleNotFound role_not_found(name, included_by) end end # Expand a run list from the chef-server API. class RunListExpansionFromAPI < RunListExpansion def rest @rest ||= (source || Chef::REST.new(Chef::Config[:chef_server_url])) end def fetch_role(name, included_by) rest.get_rest("roles/#{name}") rescue Net::HTTPServerException => e if e.message == '404 "Not Found"' role_not_found(name, included_by) else raise end end end end end chef-11.8.2/lib/chef/run_list/run_list_item.rb0000644000004100000410000000643112254362222021260 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. class Chef class RunList class RunListItem QUALIFIED_RECIPE = %r{^recipe\[([^\]@]+)(@([0-9]+(\.[0-9]+){1,2}))?\]$} QUALIFIED_ROLE = %r{^role\[([^\]]+)\]$} VERSIONED_UNQUALIFIED_RECIPE = %r{^([^@]+)(@([0-9]+(\.[0-9]+){1,2}))$} FALSE_FRIEND = %r{[\[\]]} attr_reader :name, :type, :version def initialize(item) @version = nil case item when Hash assert_hash_is_valid_run_list_item!(item) @type = (item['type'] || item[:type]).to_sym @name = item['name'] || item[:name] if (item.has_key?('version') || item.has_key?(:version)) @version = item['version'] || item[:version] end when String if match = QUALIFIED_RECIPE.match(item) # recipe[recipe_name] # recipe[recipe_name@1.0.0] @type = :recipe @name = match[1] @version = match[3] if match[3] elsif match = QUALIFIED_ROLE.match(item) # role[role_name] @type = :role @name = match[1] elsif match = VERSIONED_UNQUALIFIED_RECIPE.match(item) # recipe_name@1.0.0 @type = :recipe @name = match[1] @version = match[3] if match[3] elsif match = FALSE_FRIEND.match(item) # Recipe[recipe_name] # roles[role_name] name = match[1] raise ArgumentError, "Unable to create #{self.class} from #{item.class}:#{item.inspect}: must be recipe[#{name}] or role[#{name}]" else # recipe_name @type = :recipe @name = item end else raise ArgumentError, "Unable to create #{self.class} from #{item.class}:#{item.inspect}: must be a Hash or String" end end def to_s "#{@type}[#{@name}#{@version ? "@#{@version}" :""}]" end def role? @type == :role end def recipe? @type == :recipe end def ==(other) if other.kind_of?(String) self.to_s == other.to_s else other.respond_to?(:type) && other.respond_to?(:name) && other.respond_to?(:version) && other.type == @type && other.name == @name && other.version == @version end end def assert_hash_is_valid_run_list_item!(item) unless (item.key?('type')|| item.key?(:type)) && (item.key?('name') || item.key?(:name)) raise ArgumentError, "Initializing a #{self.class} from a hash requires that it have a 'type' and 'name' key" end end end end end chef-11.8.2/lib/chef/run_list/versioned_recipe_list.rb0000644000004100000410000000435012254362222022761 0ustar www-datawww-data# # Author:: Stephen Delano () # Author:: Seth Falcon () # Copyright:: Copyright 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'chef/version_class' require 'chef/version_constraint' # Why does this class exist? # Why did we not just modify RunList/RunListItem? class Chef class RunList class VersionedRecipeList < Array def initialize super @versions = Hash.new end def add_recipe(name, version=nil) if version && @versions.has_key?(name) unless Chef::Version.new(@versions[name]) == Chef::Version.new(version) raise Chef::Exceptions::CookbookVersionConflict, "Run list requires #{name} at versions #{@versions[name]} and #{version}" end end @versions[name] = version if version self << name unless self.include?(name) end def with_versions self.map {|recipe_name| {:name => recipe_name, :version => @versions[recipe_name]}} end # Return an Array of Hashes, each of the form: # {:name => RECIPE_NAME, :version_constraint => Chef::VersionConstraint } def with_version_constraints self.map do |recipe_name| constraint = Chef::VersionConstraint.new(@versions[recipe_name]) { :name => recipe_name, :version_constraint => constraint } end end # Return an Array of Strings, each of the form: # "NAME@VERSION" def with_version_constraints_strings self.map do |recipe_name| if @versions[recipe_name] "#{recipe_name}@#{@versions[recipe_name]}" else recipe_name end end end end end end chef-11.8.2/lib/chef/version_constraint/0000755000004100000410000000000012254362222020144 5ustar www-datawww-datachef-11.8.2/lib/chef/version_constraint/platform.rb0000644000004100000410000000160112254362222022313 0ustar www-datawww-data# Author:: Xabier de Zuazo () # Copyright:: Copyright (c) 2013 Onddo Labs, SL. # License:: Apache License, Version 2.0 # # 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. require 'chef/version_constraint' require 'chef/version/platform' class Chef class VersionConstraint class Platform < Chef::VersionConstraint VERSION_CLASS = Chef::Version::Platform end end end chef-11.8.2/lib/chef/node.rb0000644000004100000410000003701012254362222015466 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Christopher Brown () # Author:: Christopher Walters () # Author:: Tim Hinderliter () # Copyright:: Copyright (c) 2008-2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'forwardable' require 'chef/config' require 'chef/nil_argument' require 'chef/mixin/params_validate' require 'chef/mixin/from_file' require 'chef/mixin/deep_merge' require 'chef/dsl/include_attribute' require 'chef/dsl/platform_introspection' require 'chef/environment' require 'chef/rest' require 'chef/run_list' require 'chef/node/attribute' require 'chef/mash' require 'chef/json_compat' require 'chef/search/query' class Chef class Node extend Forwardable def_delegators :attributes, :keys, :each_key, :each_value, :key?, :has_key? attr_accessor :recipe_list, :run_state, :run_list # RunContext will set itself as run_context via this setter when # initialized. This is needed so DSL::IncludeAttribute (in particular, # #include_recipe) can access the run_context to determine if an attributes # file has been seen yet. #-- # TODO: This is a pretty ugly way to solve that problem. attr_accessor :run_context include Chef::Mixin::FromFile include Chef::DSL::IncludeAttribute include Chef::DSL::PlatformIntrospection include Chef::Mixin::ParamsValidate # Create a new Chef::Node object. def initialize @name = nil @chef_environment = '_default' @run_list = Chef::RunList.new @attributes = Chef::Node::Attribute.new({}, {}, {}, {}) @run_state = {} end # Used by DSL def node self end def chef_server_rest Chef::REST.new(Chef::Config[:chef_server_url]) end # Set the name of this Node, or return the current name. def name(arg=nil) if arg != nil validate( {:name => arg }, {:name => { :kind_of => String, :cannot_be => :blank, :regex => /^[\-[:alnum:]_:.]+$/} }) @name = arg else @name end end def chef_environment(arg=nil) set_or_return( :chef_environment, arg, { :regex => /^[\-[:alnum:]_]+$/, :kind_of => String } ) end def chef_environment=(environment) chef_environment(environment) end alias :environment :chef_environment def attributes @attributes end alias :attribute :attributes alias :construct_attributes :attributes # Return an attribute of this node. Returns nil if the attribute is not found. def [](attrib) attributes[attrib] end # Set a normal attribute of this node, but auto-vivify any Mashes that # might be missing def normal attributes.set_unless_value_present = false attributes.normal end alias_method :set, :normal # Set a normal attribute of this node, auto-vivifying any mashes that are # missing, but if the final value already exists, don't set it def normal_unless attributes.set_unless_value_present = true attributes.normal end alias_method :set_unless, :normal_unless # Set a default of this node, but auto-vivify any Mashes that might # be missing def default attributes.set_unless_value_present = false attributes.default end # Set a force default attribute. Intermediate mashes will be created by # auto-vivify if necessary. def default! attributes.set_unless_value_present = false attributes.default! end # Set a default attribute of this node, auto-vivifying any mashes that are # missing, but if the final value already exists, don't set it def default_unless attributes.set_unless_value_present = true attributes.default end # Set an override attribute of this node, but auto-vivify any Mashes that # might be missing def override attributes.set_unless_value_present = false attributes.override end # Set a force override attribute. Intermediate mashes will be created by # auto-vivify if needed. def override! attributes.set_unless_value_present = false attributes.override! end # Set an override attribute of this node, auto-vivifying any mashes that # are missing, but if the final value already exists, don't set it def override_unless attributes.set_unless_value_present = true attributes.override end def override_attrs attributes.override end def override_attrs=(new_values) attributes.override = new_values end def default_attrs attributes.default end def default_attrs=(new_values) attributes.default = new_values end def normal_attrs attributes.normal end def normal_attrs=(new_values) attributes.normal = new_values end def automatic_attrs attributes.automatic end def automatic_attrs=(new_values) attributes.automatic = new_values end # Return true if this Node has a given attribute, false if not. Takes either a symbol or # a string. # # Only works on the top level. Preferred way is to use the normal [] style # lookup and call attribute?() def attribute?(attrib) attributes.attribute?(attrib) end # Yield each key of the top level to the block. def each(&block) attributes.each(&block) end # Iterates over each attribute, passing the attribute and value to the block. def each_attribute(&block) attributes.each_attribute(&block) end # Only works for attribute fetches, setting is no longer supported def method_missing(symbol, *args) attributes.send(symbol, *args) end # Returns true if this Node expects a given recipe, false if not. # # First, the run list is consulted to see whether the recipe is # explicitly included. If it's not there, it looks in # `node[:recipes]`, which is populated when the run_list is expanded # # NOTE: It's used by cookbook authors def recipe?(recipe_name) run_list.include?(recipe_name) || Array(self[:recipes]).include?(recipe_name) end # Returns true if this Node expects a given role, false if not. def role?(role_name) run_list.include?("role[#{role_name}]") end # Returns an Array of roles and recipes, in the order they will be applied. # If you call it with arguments, they will become the new list of roles and recipes. def run_list(*args) args.length > 0 ? @run_list.reset!(args) : @run_list end # Returns true if this Node expects a given role, false if not. def run_list?(item) run_list.detect { |r| r == item } ? true : false end # Consume data from ohai and Attributes provided as JSON on the command line. def consume_external_attrs(ohai_data, json_cli_attrs) Chef::Log.debug("Extracting run list from JSON attributes provided on command line") consume_attributes(json_cli_attrs) self.automatic_attrs = ohai_data platform, version = Chef::Platform.find_platform_and_version(self) Chef::Log.debug("Platform is #{platform} version #{version}") self.automatic[:platform] = platform self.automatic[:platform_version] = version end # Consumes the combined run_list and other attributes in +attrs+ def consume_attributes(attrs) normal_attrs_to_merge = consume_run_list(attrs) Chef::Log.debug("Applying attributes from json file") self.normal_attrs = Chef::Mixin::DeepMerge.merge(normal_attrs,normal_attrs_to_merge) self.tags # make sure they're defined end # Lazy initializer for tags attribute def tags normal[:tags] = [] unless attribute?(:tags) normal[:tags] end def tag(*tags) tags.each do |tag| self.normal[:tags].push(tag.to_s) unless self[:tags].include? tag.to_s end self[:tags] end # Extracts the run list from +attrs+ and applies it. Returns the remaining attributes def consume_run_list(attrs) attrs = attrs ? attrs.dup : {} if new_run_list = attrs.delete("recipes") || attrs.delete("run_list") if attrs.key?("recipes") || attrs.key?("run_list") raise Chef::Exceptions::AmbiguousRunlistSpecification, "please set the node's run list using the 'run_list' attribute only." end Chef::Log.info("Setting the run_list to #{new_run_list.inspect} from JSON") run_list(new_run_list) end attrs end # Clear defaults and overrides, so that any deleted attributes # between runs are still gone. def reset_defaults_and_overrides self.default.clear self.override.clear end # Expands the node's run list and sets the default and override # attributes. Also applies stored attributes (from json provided # on the command line) # # Returns the fully-expanded list of recipes, a RunListExpansion. # #-- # TODO: timh/cw, 5-14-2010: Should this method exist? Should we # instead modify default_attrs and override_attrs whenever our # run_list is mutated? Or perhaps do something smarter like # on-demand generation of default_attrs and override_attrs, # invalidated only when run_list is mutated? def expand!(data_source = 'server') expansion = run_list.expand(chef_environment, data_source) raise Chef::Exceptions::MissingRole, expansion if expansion.errors? self.tags # make sure they're defined automatic_attrs[:recipes] = expansion.recipes automatic_attrs[:roles] = expansion.roles apply_expansion_attributes(expansion) expansion end # Apply the default and overrides attributes from the expansion # passed in, which came from roles. def apply_expansion_attributes(expansion) loaded_environment = if chef_environment == "_default" Chef::Environment.new.tap {|e| e.name("_default")} else Chef::Environment.load(chef_environment) end attributes.env_default = loaded_environment.default_attributes attributes.env_override = loaded_environment.override_attributes attribute.role_default = expansion.default_attrs attributes.role_override = expansion.override_attrs end # Transform the node to a Hash def to_hash index_hash = Hash.new index_hash["chef_type"] = "node" index_hash["name"] = name index_hash["chef_environment"] = chef_environment attribute.each do |key, value| index_hash[key] = value end index_hash["recipe"] = run_list.recipe_names if run_list.recipe_names.length > 0 index_hash["role"] = run_list.role_names if run_list.role_names.length > 0 index_hash["run_list"] = run_list.run_list if run_list.run_list.length > 0 index_hash end def display_hash display = {} display["name"] = name display["chef_environment"] = chef_environment display["automatic"] = automatic_attrs display["normal"] = normal_attrs display["default"] = attributes.combined_default display["override"] = attributes.combined_override display["run_list"] = run_list.run_list display end # Serialize this object as a hash def to_json(*a) for_json.to_json(*a) end def for_json result = { "name" => name, "chef_environment" => chef_environment, 'json_class' => self.class.name, "automatic" => attributes.automatic, "normal" => attributes.normal, "chef_type" => "node", "default" => attributes.combined_default, "override" => attributes.combined_override, #Render correctly for run_list items so malformed json does not result "run_list" => run_list.run_list.map { |item| item.to_s } } result end def update_from!(o) run_list.reset!(o.run_list) self.automatic_attrs = o.automatic_attrs self.normal_attrs = o.normal_attrs self.override_attrs = o.override_attrs self.default_attrs = o.default_attrs chef_environment(o.chef_environment) self end # Create a Chef::Node from JSON def self.json_create(o) node = new node.name(o["name"]) node.chef_environment(o["chef_environment"]) if o.has_key?("attributes") node.normal_attrs = o["attributes"] end node.automatic_attrs = Mash.new(o["automatic"]) if o.has_key?("automatic") node.normal_attrs = Mash.new(o["normal"]) if o.has_key?("normal") node.default_attrs = Mash.new(o["default"]) if o.has_key?("default") node.override_attrs = Mash.new(o["override"]) if o.has_key?("override") if o.has_key?("run_list") node.run_list.reset!(o["run_list"]) else o["recipes"].each { |r| node.recipes << r } end node end def self.list_by_environment(environment, inflate=false) if inflate response = Hash.new Chef::Search::Query.new.search(:node, "chef_environment:#{environment}") {|n| response[n.name] = n unless n.nil?} response else Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("environments/#{environment}/nodes") end end def self.list(inflate=false) if inflate response = Hash.new Chef::Search::Query.new.search(:node) do |n| response[n.name] = n unless n.nil? end response else Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("nodes") end end def self.find_or_create(node_name) load(node_name) rescue Net::HTTPServerException => e raise unless e.response.code == '404' node = build(node_name) node.create end def self.build(node_name) node = new node.name(node_name) node.chef_environment(Chef::Config[:environment]) unless Chef::Config[:environment].nil? || Chef::Config[:environment].chop.empty? node end # Load a node by name def self.load(name) Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("nodes/#{name}") end # Remove this node via the REST API def destroy chef_server_rest.delete_rest("nodes/#{name}") end # Save this node via the REST API def save # Try PUT. If the node doesn't yet exist, PUT will return 404, # so then POST to create. begin if Chef::Config[:why_run] Chef::Log.warn("In whyrun mode, so NOT performing node save.") else chef_server_rest.put_rest("nodes/#{name}", self) end rescue Net::HTTPServerException => e raise e unless e.response.code == "404" chef_server_rest.post_rest("nodes", self) end self end # Create the node via the REST API def create chef_server_rest.post_rest("nodes", self) self end def to_s "node[#{name}]" end def <=>(other_node) self.name <=> other_node.name end end end chef-11.8.2/lib/chef/recipe.rb0000644000004100000410000000650512254362222016015 0ustar www-datawww-data#-- # Author:: Adam Jacob () # Author:: Christopher Walters () # Copyright:: Copyright (c) 2008, 2009 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/dsl/recipe' require 'chef/dsl/data_query' require 'chef/dsl/platform_introspection' require 'chef/dsl/include_recipe' require 'chef/dsl/registry_helper' require 'chef/mixin/from_file' require 'chef/mixin/deprecation' class Chef # == Chef::Recipe # A Recipe object is the context in which Chef recipes are evaluated. class Recipe include Chef::DSL::DataQuery include Chef::DSL::PlatformIntrospection include Chef::DSL::IncludeRecipe include Chef::DSL::Recipe include Chef::DSL::RegistryHelper include Chef::Mixin::FromFile include Chef::Mixin::Deprecation attr_accessor :cookbook_name, :recipe_name, :recipe, :params, :run_context # Parses a potentially fully-qualified recipe name into its # cookbook name and recipe short name. # # For example: # "aws::elastic_ip" returns [:aws, "elastic_ip"] # "aws" returns [:aws, "default"] #-- # TODO: Duplicates functionality of RunListItem def self.parse_recipe_name(recipe_name) rmatch = recipe_name.match(/(.+?)::(.+)/) if rmatch [ rmatch[1].to_sym, rmatch[2] ] else [ recipe_name.to_sym, "default" ] end end def initialize(cookbook_name, recipe_name, run_context) @cookbook_name = cookbook_name @recipe_name = recipe_name @run_context = run_context # TODO: 5/19/2010 cw/tim: determine whether this can be removed @params = Hash.new @node = deprecated_ivar(run_context.node, :node, :warn) end # Used in DSL mixins def node run_context.node end # Used by the DSL to look up resources when executing in the context of a # recipe. def resources(*args) run_context.resource_collection.find(*args) end # This was moved to Chef::Node#tag, redirecting here for compatability def tag(*tags) run_context.node.tag(*tags) end # Returns true if the node is tagged with *all* of the supplied +tags+. # # === Parameters # tags:: A list of tags # # === Returns # true:: If all the parameters are present # false:: If any of the parameters are missing def tagged?(*tags) tags.each do |tag| return false unless run_context.node[:tags].include?(tag) end true end # Removes the list of tags from the node. # # === Parameters # tags:: A list of tags # # === Returns # tags:: The current list of run_context.node[:tags] def untag(*tags) tags.each do |tag| run_context.node.normal[:tags].delete(tag) end end end end chef-11.8.2/lib/chef/exceptions.rb0000644000004100000410000002660012254362222016725 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Seth Falcon () # Author:: Kyle Goodwin () # Copyright:: Copyright 2008-2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. class Chef # == Chef::Exceptions # Chef's custom exceptions are all contained within the Chef::Exceptions # namespace. class Exceptions # Backcompat with Chef::ShellOut code: require 'mixlib/shellout/exceptions' def self.const_missing(const_name) if const_name == :ShellCommandFailed Chef::Log.warn("Chef::Exceptions::ShellCommandFailed is deprecated, use Mixlib::ShellOut::ShellCommandFailed") called_from = caller[0..3].inject("Called from:\n") {|msg, trace_line| msg << " #{trace_line}\n" } Chef::Log.warn(called_from) Mixlib::ShellOut::ShellCommandFailed else super end end class Application < RuntimeError; end class Cron < RuntimeError; end class Env < RuntimeError; end class Exec < RuntimeError; end class ErlCall < RuntimeError; end class FileNotFound < RuntimeError; end class Package < RuntimeError; end class Service < RuntimeError; end class Route < RuntimeError; end class SearchIndex < RuntimeError; end class Override < RuntimeError; end class UnsupportedAction < RuntimeError; end class MissingLibrary < RuntimeError; end class CannotDetermineNodeName < RuntimeError; end class User < RuntimeError; end class Group < RuntimeError; end class Link < RuntimeError; end class Mount < RuntimeError; end class PrivateKeyMissing < RuntimeError; end class CannotWritePrivateKey < RuntimeError; end class RoleNotFound < RuntimeError; end class ValidationFailed < ArgumentError; end class InvalidPrivateKey < ArgumentError; end class ConfigurationError < ArgumentError; end class RedirectLimitExceeded < RuntimeError; end class AmbiguousRunlistSpecification < ArgumentError; end class CookbookFrozen < ArgumentError; end class CookbookNotFound < RuntimeError; end # Cookbook loader used to raise an argument error when cookbook not found. # for back compat, need to raise an error that inherits from ArgumentError class CookbookNotFoundInRepo < ArgumentError; end class RecipeNotFound < ArgumentError; end class AttributeNotFound < RuntimeError; end class InvalidCommandOption < RuntimeError; end class CommandTimeout < RuntimeError; end class RequestedUIDUnavailable < RuntimeError; end class InvalidHomeDirectory < ArgumentError; end class DsclCommandFailed < RuntimeError; end class UserIDNotFound < ArgumentError; end class GroupIDNotFound < ArgumentError; end class InvalidResourceReference < RuntimeError; end class ResourceNotFound < RuntimeError; end class InvalidResourceSpecification < ArgumentError; end class SolrConnectionError < RuntimeError; end class IllegalChecksumRevert < RuntimeError; end class CookbookVersionNameMismatch < ArgumentError; end class MissingParentDirectory < RuntimeError; end class UnresolvableGitReference < RuntimeError; end class InvalidRemoteGitReference < RuntimeError; end class InvalidEnvironmentRunListSpecification < ArgumentError; end class InvalidDataBagItemID < ArgumentError; end class InvalidDataBagName < ArgumentError; end class EnclosingDirectoryDoesNotExist < ArgumentError; end # Errors originating from calls to the Win32 API class Win32APIError < RuntimeError; end # Thrown when Win32 API layer binds to non-existent Win32 function. Occurs # when older versions of Windows don't support newer Win32 API functions. class Win32APIFunctionNotImplemented < NotImplementedError; end # Attempting to run windows code on a not-windows node class Win32NotWindows < RuntimeError; end class WindowsNotAdmin < RuntimeError; end # Attempting to access a 64-bit only resource on a 32-bit Windows system class Win32ArchitectureIncorrect < RuntimeError; end class ObsoleteDependencySyntax < ArgumentError; end class InvalidDataBagPath < ArgumentError; end # A different version of a cookbook was added to a # VersionedRecipeList than the one already there. class CookbookVersionConflict < ArgumentError ; end # does not follow X.Y.Z format. ArgumentError? class InvalidPlatformVersion < ArgumentError; end class InvalidCookbookVersion < ArgumentError; end # version constraint should be a string or array, or it doesn't # match OP VERSION. ArgumentError? class InvalidVersionConstraint < ArgumentError; end # Version constraints are not allowed in chef-solo class IllegalVersionConstraint < NotImplementedError; end # File operation attempted but no permissions to perform it class InsufficientPermissions < RuntimeError; end # Ifconfig failed class Ifconfig < RuntimeError; end # Invalid "source" parameter to a remote_file resource class InvalidRemoteFileURI < ArgumentError; end # Node::Attribute computes the merged version of of attributes # and makes it read-only. Attempting to modify a read-only # attribute will cause this error. class ImmutableAttributeModification < NoMethodError; end # Merged node attributes are invalidated when the component # attributes are updated. Attempting to read from a stale copy # of merged attributes will trigger this error. class StaleAttributeRead < StandardError; end # Registry Helper throws the following errors class Win32RegArchitectureIncorrect < Win32ArchitectureIncorrect; end class Win32RegHiveMissing < ArgumentError; end class Win32RegKeyMissing < RuntimeError; end class Win32RegValueMissing < RuntimeError; end class Win32RegDataMissing < RuntimeError; end class Win32RegValueExists < RuntimeError; end class Win32RegNoRecursive < ArgumentError; end class Win32RegTypeDoesNotExist < ArgumentError; end class Win32RegBadType < ArgumentError; end class Win32RegBadValueSize < ArgumentError; end class Win32RegTypesMismatch < ArgumentError; end class InvalidEnvironmentPath < ArgumentError; end class EnvironmentNotFound < RuntimeError; end # File-like resource found a non-file (socket, pipe, directory, etc) at its destination class FileTypeMismatch < RuntimeError; end # File (or descendent) resource configured to manage symlink source, but # the symlink that is there either loops or points to a nonexistent file class InvalidSymlink < RuntimeError; end class ChildConvergeError < RuntimeError; end class MissingRole < RuntimeError NULL = Object.new attr_reader :expansion def initialize(message_or_expansion=NULL) @expansion = nil case message_or_expansion when NULL super() when String super when RunList::RunListExpansion @expansion = message_or_expansion missing_roles = @expansion.errors.join(', ') super("The expanded run list includes nonexistent roles: #{missing_roles}") end end end # Exception class for collecting multiple failures. Used when running # delayed notifications so that chef can process each delayed # notification even if chef client or other notifications fail. class MultipleFailures < StandardError def initialize(*args) super @all_failures = [] end def message base = "Multiple failures occurred:\n" @all_failures.inject(base) do |message, (location, error)| message << "* #{error.class} occurred in #{location}: #{error.message}\n" end end def client_run_failure(exception) set_backtrace(exception.backtrace) @all_failures << [ "chef run", exception ] end def notification_failure(exception) @all_failures << [ "delayed notification", exception ] end def raise! unless empty? raise self.for_raise end end def empty? @all_failures.empty? end def for_raise if @all_failures.size == 1 @all_failures[0][1] else self end end end class CookbookVersionSelection # Compound exception: In run_list expansion and resolution, # run_list items referred to cookbooks that don't exist and/or # have no versions available. class InvalidRunListItems < StandardError attr_reader :non_existent_cookbooks attr_reader :cookbooks_with_no_matching_versions def initialize(message, non_existent_cookbooks, cookbooks_with_no_matching_versions) super(message) @non_existent_cookbooks = non_existent_cookbooks @cookbooks_with_no_matching_versions = cookbooks_with_no_matching_versions end def to_json(*a) result = { "message" => message, "non_existent_cookbooks" => non_existent_cookbooks, "cookbooks_with_no_versions" => cookbooks_with_no_matching_versions } result.to_json(*a) end end # In run_list expansion and resolution, a constraint was # unsatisfiable. # # This exception may not be the complete error report. If you # resolve the misconfiguration represented by this exception and # re-solve, you may get another exception class UnsatisfiableRunListItem < StandardError attr_reader :run_list_item attr_reader :non_existent_cookbooks, :most_constrained_cookbooks # most_constrained_cookbooks: if I were to remove constraints # regarding these cookbooks, I would get a solution or move on # to the next error (deeper in the graph). An item in this list # may be unsatisfiable, but when resolved may also reveal # further unsatisfiable constraints; this condition would not be # reported. def initialize(message, run_list_item, non_existent_cookbooks, most_constrained_cookbooks) super(message) @run_list_item = run_list_item @non_existent_cookbooks = non_existent_cookbooks @most_constrained_cookbooks = most_constrained_cookbooks end def to_json(*a) result = { "message" => message, "unsatisfiable_run_list_item" => run_list_item, "non_existent_cookbooks" => non_existent_cookbooks, "most_constrained_cookbooks" => most_constrained_cookbooks } result.to_json(*a) end end end # CookbookVersionSelection # When the server sends a redirect, RFC 2616 states a user-agent should # not follow it with a method other than GET or HEAD, unless a specific # action is taken by the user. A redirect received as response to a # non-GET and non-HEAD request will thus raise an InvalidRedirect. class InvalidRedirect < StandardError; end end end chef-11.8.2/lib/chef/event_dispatch/0000755000004100000410000000000012254362222017213 5ustar www-datawww-datachef-11.8.2/lib/chef/event_dispatch/base.rb0000644000004100000410000002310112254362222020447 0ustar www-datawww-dataclass Chef # ==EventDispatch # Classes in EventDispatch deal with collecting, distributing, and handling # information in response to events that occur during a chef-client run. # # EventDispatch uses a simple publishing system where data from all events # are forwarded to all subscribers unconditionally. # # EventDispatch is used to implement custom console output formatters so that # users may have more control over the formatting and verbosity of Chef # client output and client-side data collection for server-side client # history storage and reporting. # # === API Stability Status # The EventDispatch API is intended to become a stable, public API upon which # end-users can implement their own custom output formatters, reporting # integration libraries, and more. This is a new feature, however, so # breaking changes may be required as it "bakes" in order to provide a clean, # coherent and supportable API in the long term. Therefore, developers should # consider the feature "beta" for now and be prepared for possible breaking # changes in point releases. module EventDispatch # == EventDispatch::Base # EventDispatch::Base is a completely abstract base class that defines the # API used by both the classes that collect event information and those # that process them. class Base # Called at the very start of a Chef Run def run_start(version) end def run_started(run_status) end # Called at the end a successful Chef run. def run_completed(node) end # Called at the end of a failed Chef run. def run_failed(exception) end # Called right after ohai runs. def ohai_completed(node) end # Already have a client key, assuming this node has registered. def skipping_registration(node_name, config) end # About to attempt to register as +node_name+ def registration_start(node_name, config) end def registration_completed end # Failed to register this client with the server. def registration_failed(node_name, exception, config) end # Called before Chef client loads the node data from the server def node_load_start(node_name, config) end # TODO: def node_run_list_overridden(*args) # Failed to load node data from the server def node_load_failed(node_name, exception, config) end # Error expanding the run list def run_list_expand_failed(node, exception) end # Called after Chef client has loaded the node data. # Default and override attrs from roles have been computed, but not yet applied. # Normal attrs from JSON have been added to the node. def node_load_completed(node, expanded_run_list, config) end # Called before the cookbook collection is fetched from the server. def cookbook_resolution_start(expanded_run_list) end # Called when there is an error getting the cookbook collection from the # server. def cookbook_resolution_failed(expanded_run_list, exception) end # Called when the cookbook collection is returned from the server. def cookbook_resolution_complete(cookbook_collection) end # Called before unneeded cookbooks are removed def cookbook_clean_start end # Called after the file at +path+ is removed. It may be removed if the # cookbook containing it was removed from the run list, or if the file was # removed from the cookbook. def removed_cookbook_file(path) end # Called when cookbook cleaning is finished. def cookbook_clean_complete end # Called before cookbook sync starts def cookbook_sync_start(cookbook_count) end # Called when cookbook +cookbook_name+ has been sync'd def synchronized_cookbook(cookbook_name) end # Called when an individual file in a cookbook has been updated def updated_cookbook_file(cookbook_name, path) end # Called when an error occurs during cookbook sync def cookbook_sync_failed(cookbooks, exception) end # Called after all cookbooks have been sync'd. def cookbook_sync_complete end ## TODO: add cookbook name to the API for file load callbacks ## TODO: add callbacks for overall cookbook eval start and complete. # Called when library file loading starts def library_load_start(file_count) end # Called when library file has been loaded def library_file_loaded(path) end # Called when a library file has an error on load. def library_file_load_failed(path, exception) end # Called when library file loading has finished def library_load_complete end # Called when LWRP loading starts def lwrp_load_start(lwrp_file_count) end # Called after a LWR or LWP has been loaded def lwrp_file_loaded(path) end # Called after a LWR or LWP file errors on load def lwrp_file_load_failed(path, exception) end # Called when LWRPs are finished loading def lwrp_load_complete end # Called before attribute files are loaded def attribute_load_start(attribute_file_count) end # Called after the attribute file is loaded def attribute_file_loaded(path) end # Called when an attribute file fails to load. def attribute_file_load_failed(path, exception) end # Called when attribute file loading is finished def attribute_load_complete end # Called before resource definitions are loaded def definition_load_start(definition_file_count) end # Called when a resource definition has been loaded def definition_file_loaded(path) end # Called when a resource definition file fails to load def definition_file_load_failed(path, exception) end # Called when resource defintions are done loading def definition_load_complete end # Called before recipes are loaded def recipe_load_start(recipe_count) end # Called after the recipe has been loaded def recipe_file_loaded(path) end # Called after a recipe file fails to load def recipe_file_load_failed(path, exception) end # Called when a recipe cannot be resolved def recipe_not_found(exception) end # Called when recipes have been loaded. def recipe_load_complete end # Called before convergence starts def converge_start(run_context) end # Called when the converge phase is finished. def converge_complete end # TODO: need events for notification resolve? # def notifications_resolved # end # Called before action is executed on a resource. def resource_action_start(resource, action, notification_type=nil, notifier=nil) end # Called when a resource fails, but will retry. def resource_failed_retriable(resource, action, retry_count, exception) end # Called when a resource fails and will not be retried. def resource_failed(resource, action, exception) end # Called when a resource action has been skipped b/c of a conditional def resource_skipped(resource, action, conditional) end # Called when a resource action has been completed def resource_completed(resource) end # Called after #load_current_resource has run. def resource_current_state_loaded(resource, action, current_resource) end # Called when resource current state load is skipped due to the provider # not supporting whyrun mode. def resource_current_state_load_bypassed(resource, action, current_resource) end # Called when evaluating a resource that does not support whyrun in whyrun mode def resource_bypassed(resource, action, current_resource) end # Called when a resource has no converge actions, e.g., it was already correct. def resource_up_to_date(resource, action) end # Called when a change has been made to a resource. May be called multiple # times per resource, e.g., a file may have its content updated, and then # its permissions updated. def resource_update_applied(resource, action, update) end # Called after a resource has been completely converged, but only if # modifications were made. def resource_updated(resource, action) end # Called before handlers run def handlers_start(handler_count) end # Called after an individual handler has run def handler_executed(handler) end # Called after all handlers have executed def handlers_completed end # Called when an assertion declared by a provider fails def provider_requirement_failed(action, resource, exception, message) end # Called when a provider makes an assumption after a failed assertion # in whyrun mode, in order to allow execution to continue def whyrun_assumption(action, resource, message) end ## TODO: deprecation warning. this way we can queue them up and present # them all at once. # An uncategorized message. This supports the case that a user needs to # pass output that doesn't fit into one of the callbacks above. Note that # there's no semantic information about the content or importance of the # message. That means that if you're using this too often, you should add a # callback for it. def msg(message) end end end end chef-11.8.2/lib/chef/event_dispatch/dispatcher.rb0000644000004100000410000000215712254362222021673 0ustar www-datawww-datarequire 'chef/event_dispatch/base' class Chef module EventDispatch # == EventDispatch::Dispatcher # The Dispatcher handles receiving event data from the sources # (Chef::Client, Resources and Providers, etc.) and publishing the data to # the registered subscribers. class Dispatcher < Base def initialize(*subscribers) @subscribers = subscribers end # Add a new subscriber to the list of registered subscribers def register(subscriber) @subscribers << subscriber end #### # All messages are unconditionally forwarded to all subscribers, so just # define the forwarding in one go: # # Define a method that will be forwarded to all def self.def_forwarding_method(method_name) class_eval(<<-END_OF_METHOD, __FILE__, __LINE__) def #{method_name}(*args) @subscribers.each {|s| s.#{method_name}(*args)} end END_OF_METHOD end (Base.instance_methods - Object.instance_methods).each do |method_name| def_forwarding_method(method_name) end end end end chef-11.8.2/lib/chef/resource_platform_map.rb0000644000004100000410000001102612254362222021130 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/mixin/params_validate' require 'chef/mixin/convert_to_class_name' class Chef class Resource class PlatformMap include Chef::Mixin::ParamsValidate include Chef::Mixin::ConvertToClassName attr_reader :map def initialize(map={:default => {}}) @map = map end def filter(platform, version) resource_map = map[:default].clone platform_sym = platform if platform.kind_of?(String) platform.downcase! platform.gsub!(/\s/, "_") platform_sym = platform.to_sym end if map.has_key?(platform_sym) if map[platform_sym].has_key?(version) if map[platform_sym].has_key?(:default) resource_map.merge!(map[platform_sym][:default]) end resource_map.merge!(map[platform_sym][version]) elsif map[platform_sym].has_key?(:default) resource_map.merge!(map[platform_sym][:default]) end end resource_map end def set(args) validate( args, { :platform => { :kind_of => Symbol, :required => false }, :version => { :kind_of => String, :required => false }, :short_name => { :kind_of => Symbol, :required => true }, :resource => { :kind_of => [ String, Symbol, Class ], :required => true } } ) if args.has_key?(:platform) if args.has_key?(:version) if map.has_key?(args[:platform]) if map[args[:platform]].has_key?(args[:version]) map[args[:platform]][args[:version]][args[:short_name].to_sym] = args[:resource] else map[args[:platform]][args[:version]] = { args[:short_name].to_sym => args[:resource] } end else map[args[:platform]] = { args[:version] => { args[:short_name].to_sym => args[:resource] } } end else if map.has_key?(args[:platform]) if map[args[:platform]].has_key?(:default) map[args[:platform]][:default][args[:short_name].to_sym] = args[:resource] else map[args[:platform]] = { :default => { args[:short_name].to_sym => args[:resource] } } end else map[args[:platform]] = { :default => { args[:short_name].to_sym => args[:resource] } } end end else if map.has_key?(:default) map[:default][args[:short_name].to_sym] = args[:resource] else map[:default] = { args[:short_name].to_sym => args[:resource] } end end end def get(short_name, platform=nil, version=nil) resource_klass = platform_resource(short_name, platform, version) || resource_matching_short_name(short_name) raise NameError, "Cannot find a resource for #{short_name} on #{platform} version #{version}" if resource_klass.nil? resource_klass end private def platform_resource(short_name, platform, version) pmap = filter(platform, version) rtkey = short_name.kind_of?(Chef::Resource) ? short_name.resource_name.to_sym : short_name pmap.has_key?(rtkey) ? pmap[rtkey] : nil end def resource_matching_short_name(short_name) begin rname = convert_to_class_name(short_name.to_s) Chef::Resource.const_get(rname) rescue NameError nil end end end end end chef-11.8.2/lib/chef/run_status.rb0000644000004100000410000000616712254362222016761 0ustar www-datawww-data# # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # # == Chef::RunStatus # Tracks various aspects of a Chef run, including the Node and RunContext, # start and end time, and any Exception that stops the run. RunStatus objects # are passed to any notification or exception handlers at the completion of a # Chef run. class Chef::RunStatus attr_reader :events attr_reader :run_context attr_writer :run_context attr_reader :start_time attr_reader :end_time attr_reader :exception attr_writer :exception def initialize(node, events) @node = node @events = events end def node @node end # sets +start_time+ to the current time. def start_clock @start_time = Time.now end # sets +end_time+ to the current time def stop_clock @end_time = Time.now end # The elapsed time between +start_time+ and +end_time+. Returns +nil+ if # either value is not set. def elapsed_time if @start_time && @end_time @end_time - @start_time else nil end end # The list of all resources in the current run context's +resource_collection+ def all_resources @run_context && @run_context.resource_collection.all_resources end # The list of all resources in the current run context's +resource_collection+ # that are marked as updated def updated_resources @run_context && @run_context.resource_collection.select { |r| r.updated } end # The backtrace from +exception+, if any def backtrace @exception && @exception.backtrace end # Did the Chef run fail? def failed? !success? end # Did the chef run succeed? returns +true+ if no exception has been set. def success? @exception.nil? end # A Hash representation of the RunStatus, with the following (Symbol) keys: # * :node # * :success # * :start_time # * :end_time # * :elapsed_time # * :all_resources # * :updated_resources # * :exception # * :backtrace def to_hash # use a flat hash here so we can't errors from intermediate values being nil { :node => node, :success => success?, :start_time => start_time, :end_time => end_time, :elapsed_time => elapsed_time, :all_resources => all_resources, :updated_resources => updated_resources, :exception => formatted_exception, :backtrace => backtrace} end # Returns a string of the format "ExceptionClass: message" or +nil+ if no # +exception+ is set. def formatted_exception @exception && "#{@exception.class.name}: #{@exception.message}" end end chef-11.8.2/lib/chef/version/0000755000004100000410000000000012254362222015700 5ustar www-datawww-datachef-11.8.2/lib/chef/version/platform.rb0000644000004100000410000000237612254362222020061 0ustar www-datawww-data# Author:: Xabier de Zuazo () # Copyright:: Copyright (c) 2013 Onddo Labs, SL. # License:: Apache License, Version 2.0 # # 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. require 'chef/version_class' class Chef class Version class Platform < Chef::Version protected def parse(str="") @major, @minor, @patch = case str.to_s when /^(\d+)\.(\d+)\.(\d+)$/ [ $1.to_i, $2.to_i, $3.to_i ] when /^(\d+)\.(\d+)$/ [ $1.to_i, $2.to_i, 0 ] when /^(\d+)$/ [ $1.to_i, 0, 0 ] else msg = "'#{str.to_s}' does not match 'x.y.z', 'x.y' or 'x'" raise Chef::Exceptions::InvalidPlatformVersion.new( msg ) end end end end end chef-11.8.2/lib/chef/dsl.rb0000644000004100000410000000031412254362222015320 0ustar www-datawww-datarequire 'chef/dsl/recipe' require 'chef/dsl/platform_introspection' require 'chef/dsl/data_query' require 'chef/dsl/include_recipe' require 'chef/dsl/include_attribute' require 'chef/dsl/registry_helper' chef-11.8.2/lib/chef/deprecation/0000755000004100000410000000000012254362222016510 5ustar www-datawww-datachef-11.8.2/lib/chef/deprecation/mixin/0000755000004100000410000000000012254362222017634 5ustar www-datawww-datachef-11.8.2/lib/chef/deprecation/mixin/template.rb0000644000004100000410000000275512254362222022005 0ustar www-datawww-data# # Author:: Serdar Sutay () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'tempfile' require 'erubis' class Chef module Deprecation module Mixin # == Deprecation::Provider::Mixin::Template # This module contains the deprecated functions of # Chef::Mixin::Template. These functions are refactored to different # components. They are frozen and will be removed in Chef 12. # module Template def render_template(template, context) begin eruby = Erubis::Eruby.new(template) output = eruby.evaluate(context) rescue Object => e raise TemplateError.new(e, template, context) end Tempfile.open("chef-rendered-template") do |tempfile| tempfile.print(output) tempfile.close yield tempfile end end end end end end chef-11.8.2/lib/chef/deprecation/provider/0000755000004100000410000000000012254362222020342 5ustar www-datawww-datachef-11.8.2/lib/chef/deprecation/provider/cookbook_file.rb0000644000004100000410000000325412254362222023500 0ustar www-datawww-data# # Author:: Serdar Sutay () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef module Deprecation module Provider # == Deprecation::Provider::CookbookFile # This module contains the deprecated functions of # Chef::Provider::CookbookFile. These functions are refactored to # different components. They are frozen and will be removed in Chef 12. # module CookbookFile def file_cache_location @file_cache_location ||= begin cookbook = run_context.cookbook_collection[resource_cookbook] cookbook.preferred_filename_on_disk_location(node, :files, @new_resource.source, @new_resource.path) end end def resource_cookbook @new_resource.cookbook || @new_resource.cookbook_name end def content_stale? ( ! ::File.exist?(@new_resource.path)) || ( ! compare_content) end def backup_new_resource if ::File.exists?(@new_resource.path) backup @new_resource.path end end end end end end chef-11.8.2/lib/chef/deprecation/provider/file.rb0000644000004100000410000001756112254362222021620 0ustar www-datawww-data# # Author:: Serdar Sutay () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef module Deprecation module Provider # == Deprecation::Provider::File # This module contains the deprecated functions of # Chef::Provider::File. These functions are refactored to different # components. They are frozen and will be removed in Chef 12. # module File def diff_current_from_content(new_content) result = nil Tempfile.open("chef-diff") do |file| file.write new_content file.close result = diff_current file.path end result end def is_binary?(path) ::File.open(path) do |file| buff = file.read(Chef::Config[:diff_filesize_threshold]) buff = "" if buff.nil? return buff !~ /^[\r[:print:]]*$/ end end def diff_current(temp_path) suppress_resource_reporting = false return [ "(diff output suppressed by config)" ] if Chef::Config[:diff_disabled] return [ "(no temp file with new content, diff output suppressed)" ] unless ::File.exists?(temp_path) # should never happen? # solaris does not support diff -N, so create tempfile to diff against if we are creating a new file target_path = if ::File.exists?(@current_resource.path) @current_resource.path else suppress_resource_reporting = true # suppress big diffs going to resource reporting service tempfile = Tempfile.new('chef-tempfile') tempfile.path end diff_filesize_threshold = Chef::Config[:diff_filesize_threshold] diff_output_threshold = Chef::Config[:diff_output_threshold] if ::File.size(target_path) > diff_filesize_threshold || ::File.size(temp_path) > diff_filesize_threshold return [ "(file sizes exceed #{diff_filesize_threshold} bytes, diff output suppressed)" ] end # MacOSX(BSD?) diff will *sometimes* happily spit out nasty binary diffs return [ "(current file is binary, diff output suppressed)"] if is_binary?(target_path) return [ "(new content is binary, diff output suppressed)"] if is_binary?(temp_path) begin # -u: Unified diff format result = shell_out("diff -u #{target_path} #{temp_path}" ) rescue Exception => e # Should *not* receive this, but in some circumstances it seems that # an exception can be thrown even using shell_out instead of shell_out! return [ "Could not determine diff. Error: #{e.message}" ] end # diff will set a non-zero return code even when there's # valid stdout results, if it encounters something unexpected # So as long as we have output, we'll show it. if not result.stdout.empty? if result.stdout.length > diff_output_threshold [ "(long diff of over #{diff_output_threshold} characters, diff output suppressed)" ] else val = result.stdout.split("\n") val.delete("\\ No newline at end of file") @new_resource.diff(val.join("\\n")) unless suppress_resource_reporting val end elsif not result.stderr.empty? [ "Could not determine diff. Error: #{result.stderr}" ] else [ "(no diff)" ] end end def setup_acl return if Chef::Platform.windows? acl_scanner = ScanAccessControl.new(@new_resource, @current_resource) acl_scanner.set_all! end def compare_content checksum(@current_resource.path) == new_resource_content_checksum end def set_content unless compare_content description = [] description << "update content in file #{@new_resource.path} from #{short_cksum(@current_resource.checksum)} to #{short_cksum(new_resource_content_checksum)}" description << diff_current_from_content(@new_resource.content) converge_by(description) do backup @new_resource.path if ::File.exists?(@new_resource.path) ::File.open(@new_resource.path, "w") {|f| f.write @new_resource.content } Chef::Log.info("#{@new_resource} contents updated") end end end def update_new_file_state(path=@new_resource.path) if !::File.directory?(path) @new_resource.checksum(checksum(path)) end if Chef::Platform.windows? # TODO: To work around CHEF-3554, add support for Windows # equivalent, or implicit resource reporting won't work for # Windows. return end acl_scanner = ScanAccessControl.new(@new_resource, @new_resource) acl_scanner.set_all! end def set_all_access_controls if access_controls.requires_changes? converge_by(access_controls.describe_changes) do access_controls.set_all #Update file state with new access values update_new_file_state end end end def deploy_tempfile Tempfile.open(::File.basename(@new_resource.name)) do |tempfile| yield tempfile temp_res = Chef::Resource::CookbookFile.new(@new_resource.name) temp_res.path(tempfile.path) ac = Chef::FileAccessControl.new(temp_res, @new_resource, self) ac.set_all! FileUtils.mv(tempfile.path, @new_resource.path) end end def backup(file=nil) file ||= @new_resource.path if @new_resource.backup != false && @new_resource.backup > 0 && ::File.exist?(file) time = Time.now savetime = time.strftime("%Y%m%d%H%M%S") backup_filename = "#{@new_resource.path}.chef-#{savetime}" backup_filename = backup_filename.sub(/^([A-Za-z]:)/, "") #strip drive letter on Windows # if :file_backup_path is nil, we fallback to the old behavior of # keeping the backup in the same directory. We also need to to_s it # so we don't get a type error around implicit to_str conversions. prefix = Chef::Config[:file_backup_path].to_s backup_path = ::File.join(prefix, backup_filename) FileUtils.mkdir_p(::File.dirname(backup_path)) if Chef::Config[:file_backup_path] FileUtils.cp(file, backup_path, :preserve => true) Chef::Log.info("#{@new_resource} backed up to #{backup_path}") # Clean up after the number of backups slice_number = @new_resource.backup backup_files = Dir[::File.join(prefix, ".#{@new_resource.path}.chef-*")].sort { |a,b| b <=> a } if backup_files.length >= @new_resource.backup remainder = backup_files.slice(slice_number..-1) remainder.each do |backup_to_delete| FileUtils.rm(backup_to_delete) Chef::Log.info("#{@new_resource} removed backup at #{backup_to_delete}") end end end end end end end end chef-11.8.2/lib/chef/deprecation/provider/remote_file.rb0000644000004100000410000000635412254362222023171 0ustar www-datawww-data# # Author:: Serdar Sutay () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef module Deprecation module Provider # == Deprecation::Provider::RemoteFile # This module contains the deprecated functions of # Chef::Provider::RemoteFile. These functions are refactored to different # components. They are frozen and will be removed in Chef 12. # module RemoteFile def current_resource_matches_target_checksum? @new_resource.checksum && @current_resource.checksum && @current_resource.checksum =~ /^#{Regexp.escape(@new_resource.checksum)}/ end def matches_current_checksum?(candidate_file) Chef::Log.debug "#{@new_resource} checking for file existence of #{@new_resource.path}" if ::File.exists?(@new_resource.path) Chef::Log.debug "#{@new_resource} file exists at #{@new_resource.path}" @new_resource.checksum(checksum(candidate_file.path)) Chef::Log.debug "#{@new_resource} target checksum: #{@current_resource.checksum}" Chef::Log.debug "#{@new_resource} source checksum: #{@new_resource.checksum}" @new_resource.checksum == @current_resource.checksum else Chef::Log.debug "#{@new_resource} creating #{@new_resource.path}" false end end def backup_new_resource if ::File.exists?(@new_resource.path) Chef::Log.debug "#{@new_resource} checksum changed from #{@current_resource.checksum} to #{@new_resource.checksum}" backup @new_resource.path end end def source_file(source, current_checksum, &block) if absolute_uri?(source) fetch_from_uri(source, &block) elsif !Chef::Config[:solo] fetch_from_chef_server(source, current_checksum, &block) else fetch_from_local_cookbook(source, &block) end end def http_client_opts(source) opts={} # CHEF-3140 # 1. If it's already compressed, trying to compress it more will # probably be counter-productive. # 2. Some servers are misconfigured so that you GET $URL/file.tgz but # they respond with content type of tar and content encoding of gzip, # which tricks Chef::REST into decompressing the response body. In this # case you'd end up with a tar archive (no gzip) named, e.g., foo.tgz, # which is not what you wanted. if @new_resource.path =~ /gz$/ or source =~ /gz$/ opts[:disable_gzip] = true end opts end end end end end chef-11.8.2/lib/chef/deprecation/provider/template.rb0000644000004100000410000000377512254362222022516 0ustar www-datawww-data# # Author:: Serdar Sutay () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/deprecation/mixin/template' class Chef module Deprecation module Provider # == Deprecation::Provider::Template # This module contains the deprecated functions of # Chef::Provider::Template. These functions are refactored to different # components. They are frozen and will be removed in Chef 12. # module Template include Chef::Deprecation::Mixin::Template def template_finder @template_finder ||= begin Chef::Provider::TemplateFinder.new(run_context, cookbook_name, node) end end def template_location @template_file_cache_location ||= begin template_finder.find(@new_resource.source, :local => @new_resource.local, :cookbook => @new_resource.cookbook) end end def resource_cookbook @new_resource.cookbook || @new_resource.cookbook_name end def rendered(rendered_template) @new_resource.checksum(checksum(rendered_template.path)) Chef::Log.debug("Current content's checksum: #{@current_resource.checksum}") Chef::Log.debug("Rendered content's checksum: #{@new_resource.checksum}") end def content_matches? @current_resource.checksum == @new_resource.checksum end end end end end chef-11.8.2/lib/chef/deprecation/warnings.rb0000644000004100000410000000232312254362222020665 0ustar www-datawww-data# # Author:: Serdar Sutay () # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef module Deprecation module Warnings def add_deprecation_warnings_for(method_names) method_names.each do |name| m = instance_method(name) define_method(name) do |*args| Chef::Log.warn "Method '#{name}' of '#{self.class}' is deprecated. It will be removed in Chef 12." Chef::Log.warn "Please update your cookbooks accordingly. Accessed from:" caller[0..3].each {|l| Chef::Log.warn l} super(*args) end end end end end end chef-11.8.2/lib/chef/checksum/0000755000004100000410000000000012254362222016015 5ustar www-datawww-datachef-11.8.2/lib/chef/checksum/storage/0000755000004100000410000000000012254362222017461 5ustar www-datawww-datachef-11.8.2/lib/chef/checksum/storage/filesystem.rb0000644000004100000410000000334712254362222022201 0ustar www-datawww-data# # Author:: Tim Hinderliter () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. class Chef class Checksum class Storage class Filesystem def initialize(base_dir, checksum) @base_dir = base_dir @checksum = checksum end def file_location File.join(checksum_repo_directory, @checksum) end alias :to_s :file_location def checksum_repo_directory File.join(Chef::Config.checksum_path, @checksum[0..1]) end def commit(sandbox_file) FileUtils.mkdir_p(checksum_repo_directory) File.rename(sandbox_file, file_location) end def revert(original_committed_file_location) File.rename(file_location, original_committed_file_location) end # Deletes the file backing this checksum from the on-disk repo. # Purging the checksums is how users can get back to a valid state if # they've deleted files, so we silently swallow Errno::ENOENT here. def purge FileUtils.rm(file_location) rescue Errno::ENOENT true end end end end end chef-11.8.2/lib/chef/checksum/storage.rb0000644000004100000410000000134012254362222020004 0ustar www-datawww-data# # Author:: Andrea Campi () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. require 'chef/checksum/storage/filesystem' chef-11.8.2/lib/chef/node/0000755000004100000410000000000012254362222015140 5ustar www-datawww-datachef-11.8.2/lib/chef/node/immutable_collections.rb0000644000004100000410000001270512254362222022047 0ustar www-datawww-data class Chef class Node module Immutablize def immutablize(value) case value when Hash ImmutableMash.new(value) when Array ImmutableArray.new(value) else value end end end # == ImmutableArray # ImmutableArray is used to implement Array collections when reading node # attributes. # # ImmutableArray acts like an ordinary Array, except: # * Methods that mutate the array are overridden to raise an error, making # the collection more or less immutable. # * Since this class stores values computed from a parent # Chef::Node::Attribute's values, it overrides all reader methods to # detect staleness and raise an error if accessed when stale. class ImmutableArray < Array include Immutablize alias :internal_push :<< private :internal_push # A list of methods that mutate Array. Each of these is overridden to # raise an error, making this instances of this class more or less # immutable. DISALLOWED_MUTATOR_METHODS = [ :<<, :[]=, :clear, :collect!, :compact!, :default=, :default_proc=, :delete, :delete_at, :delete_if, :fill, :flatten!, :insert, :keep_if, :map!, :merge!, :pop, :push, :update, :reject!, :reverse!, :replace, :select!, :shift, :slice!, :sort!, :sort_by!, :uniq!, :unshift ] def initialize(array_data) array_data.each do |value| internal_push(immutablize(value)) end end # Redefine all of the methods that mutate a Hash to raise an error when called. # This is the magic that makes this object "Immutable" DISALLOWED_MUTATOR_METHODS.each do |mutator_method_name| # Ruby 1.8 blocks can't have block arguments, so we must use string eval: class_eval(<<-METHOD_DEFN, __FILE__, __LINE__) def #{mutator_method_name}(*args, &block) msg = "Node attributes are read-only when you do not specify which precedence level to set. " + %Q(To set an attribute use code like `node.default["key"] = "value"') raise Exceptions::ImmutableAttributeModification, msg end METHOD_DEFN end def dup Array.new(map {|e| e.dup }) end end # == ImmutableMash # ImmutableMash implements Hash/Dict behavior for reading values from node # attributes. # # ImmutableMash acts like a Mash (Hash that is indifferent to String or # Symbol keys), with some important exceptions: # * Methods that mutate state are overridden to raise an error instead. # * Methods that read from the collection are overriden so that they check # if the Chef::Node::Attribute has been modified since an instance of # this class was generated. An error is raised if the object detects that # it is stale. # * Values can be accessed in attr_reader-like fashion via method_missing. class ImmutableMash < Mash include Immutablize alias :internal_set :[]= private :internal_set DISALLOWED_MUTATOR_METHODS = [ :[]=, :clear, :collect!, :default=, :default_proc=, :delete, :delete_if, :keep_if, :map!, :merge!, :update, :reject!, :replace, :select!, :shift ] def initialize(mash_data) mash_data.each do |key, value| internal_set(key, immutablize(value)) end end alias :attribute? :has_key? # Redefine all of the methods that mutate a Hash to raise an error when called. # This is the magic that makes this object "Immutable" DISALLOWED_MUTATOR_METHODS.each do |mutator_method_name| # Ruby 1.8 blocks can't have block arguments, so we must use string eval: class_eval(<<-METHOD_DEFN, __FILE__, __LINE__) def #{mutator_method_name}(*args, &block) msg = "Node attributes are read-only when you do not specify which precedence level to set. " + %Q(To set an attribute use code like `node.default["key"] = "value"') raise Exceptions::ImmutableAttributeModification, msg end METHOD_DEFN end def method_missing(symbol, *args) if args.empty? if key?(symbol) self[symbol] else raise NoMethodError, "Undefined method or attribute `#{symbol}' on `node'" end # This will raise a ImmutableAttributeModification error: elsif symbol.to_s =~ /=$/ key_to_set = symbol.to_s[/^(.+)=$/, 1] self[key_to_set] = (args.length == 1 ? args[0] : args) else raise NoMethodError, "Undefined node attribute or method `#{symbol}' on `node'" end end # Mash uses #convert_value to mashify values on input. # Since we're handling this ourselves, override it to be a no-op def convert_value(value) value end # NOTE: #default and #default= are likely to be pretty confusing. For a # regular ruby Hash, they control what value is returned for, e.g., # hash[:no_such_key] #=> hash.default # Of course, 'default' has a specific meaning in Chef-land def dup Mash.new(self) end end end end chef-11.8.2/lib/chef/node/attribute_collections.rb0000644000004100000410000001320212254362222022064 0ustar www-datawww-data#-- # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2012 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # class Chef class Node # == AttrArray # AttrArray is identical to Array, except that it keeps a reference to the # "root" (Chef::Node::Attribute) object, and will trigger a cache # invalidation on that object when mutated. class AttrArray < Array MUTATOR_METHODS = [ :<<, :[]=, :clear, :collect!, :compact!, :default=, :default_proc=, :delete, :delete_at, :delete_if, :fill, :flatten!, :insert, :keep_if, :map!, :merge!, :pop, :push, :update, :reject!, :reverse!, :replace, :select!, :shift, :slice!, :sort!, :sort_by!, :uniq!, :unshift ] # For all of the methods that may mutate an Array, we override them to # also invalidate the cached merged_attributes on the root # Node::Attribute object. MUTATOR_METHODS.each do |mutator| class_eval(<<-METHOD_DEFN, __FILE__, __LINE__) def #{mutator}(*args, &block) root.reset_cache super end METHOD_DEFN end attr_reader :root def initialize(root, data) @root = root super(data) end def dup Array.new(map {|e| e.dup}) end end # == VividMash # VividMash is identical to a Mash, with a few exceptions: # * It has a reference to the root Chef::Node::Attribute to which it # belongs, and will trigger cache invalidation on that object when # mutated. # * It auto-vivifies, that is a reference to a missing element will result # in the creation of a new VividMash for that key. (This only works when # using the element reference method, `[]` -- other methods, such as # #fetch, work as normal). # * It supports a set_unless flag (via the root Attribute object) which # allows `||=` style behavior (`||=` does not work with # auto-vivification). This is only implemented for #[]=; methods such as # #store work as normal. # * attr_accessor style element set and get are supported via method_missing class VividMash < Mash attr_reader :root # Methods that mutate a VividMash. Each of them is overridden so that it # also invalidates the cached merged_attributes on the root Attribute # object. MUTATOR_METHODS = [ :clear, :delete, :delete_if, :keep_if, :merge!, :update, :reject!, :replace, :select!, :shift ] # For all of the mutating methods on Mash, override them so that they # also invalidate the cached `merged_attributes` on the root Attribute # object. MUTATOR_METHODS.each do |mutator| class_eval(<<-METHOD_DEFN, __FILE__, __LINE__) def #{mutator}(*args, &block) root.reset_cache super end METHOD_DEFN end def initialize(root, data={}) @root = root super(data) end def [](key) value = super if !key?(key) value = self.class.new(root) self[key] = value else value end end def []=(key, value) if set_unless? && key?(key) self[key] else root.reset_cache super end end alias :attribute? :has_key? def method_missing(symbol, *args) # Calling `puts arg` implicitly calls #to_ary on `arg`. If `arg` does # not implement #to_ary, ruby recognizes it as a single argument, and # if it returns an Array, then ruby prints each element. If we don't # account for that here, we'll auto-vivify a VividMash for the key # :to_ary which creates an unwanted key and raises a TypeError. if symbol == :to_ary super elsif args.empty? self[symbol] elsif symbol.to_s =~ /=$/ key_to_set = symbol.to_s[/^(.+)=$/, 1] self[key_to_set] = (args.length == 1 ? args[0] : args) else raise NoMethodError, "Undefined node attribute or method `#{symbol}' on `node'. To set an attribute, use `#{symbol}=value' instead." end end def set_unless? @root.set_unless? end def convert_key(key) super end # Mash uses #convert_value to mashify values on input. # We override it here to convert hash or array values to VividMash or # AttrArray for consistency and to ensure that the added parts of the # attribute tree will have the correct cache invalidation behavior. def convert_value(value) case value when VividMash value when Hash VividMash.new(root, value) when Array AttrArray.new(root, value) else value end end def dup Mash.new(self) end end end end chef-11.8.2/lib/chef/node/attribute.rb0000644000004100000410000002643012254362222017475 0ustar www-datawww-data#-- # Author:: Adam Jacob () # Author:: AJ Christensen () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/node/immutable_collections' require 'chef/node/attribute_collections' require 'chef/mixin/deep_merge' require 'chef/log' class Chef class Node # == Attribute # Attribute implements a nested key-value (Hash) and flat collection # (Array) data structure supporting multiple levels of precedence, such # that a given key may have multiple values internally, but will only # return the highest precedence value when reading. class Attribute < Mash include Immutablize include Enumerable # List of the component attribute hashes, in order of precedence, low to # high. COMPONENTS = [ :@default, :@env_default, :@role_default, :@force_default, :@normal, :@override, :@role_override, :@env_override, :@force_override, :@automatic ].freeze DEFAULT_COMPONENTS = [ :@default, :@env_default, :@role_default, :@force_default ] OVERRIDE_COMPONENTS = [ :@override, :@role_override, :@env_override, :@force_override ] [:all?, :any?, :assoc, :chunk, :collect, :collect_concat, :compare_by_identity, :compare_by_identity?, :count, :cycle, :detect, :drop, :drop_while, :each, :each_cons, :each_entry, :each_key, :each_pair, :each_slice, :each_value, :each_with_index, :each_with_object, :empty?, :entries, :except, :fetch, :find, :find_all, :find_index, :first, :flat_map, :flatten, :grep, :group_by, :has_value?, :include?, :index, :inject, :invert, :key, :keys, :length, :map, :max, :max_by, :merge, :min, :min_by, :minmax, :minmax_by, :none?, :one?, :partition, :rassoc, :reduce, :reject, :reverse_each, :select, :size, :slice_before, :sort, :sort_by, :store, :symbolize_keys, :take, :take_while, :to_a, :to_hash, :to_set, :value?, :values, :values_at, :zip].each do |delegated_method| class_eval(<<-METHOD_DEFN) def #{delegated_method}(*args, &block) merged_attributes.send(:#{delegated_method}, *args, &block) end METHOD_DEFN end # return the cookbook level default attribute component attr_reader :default # return the role level default attribute component attr_reader :role_default # return the environment level default attribute component attr_reader :env_default # return the force_default level attribute component attr_reader :force_default # default! is the "advertised" method for force_default, but is # implemented as an alias because instance variables can't (easily) have # +!+ characters. alias :default! :force_default # return the "normal" level attribute component attr_reader :normal # return the cookbook level override attribute component attr_reader :override # return the role level override attribute component attr_reader :role_override # return the enviroment level override attribute component attr_reader :env_override # return the force override level attribute component attr_reader :force_override # +override!+ is the "advertised" method for +force_override+ but is # implemented as an alias because instance variables can't easily have # +!+ characters. alias :override! :force_override # return the automatic level attribute component attr_reader :automatic def initialize(normal, default, override, automatic) @set_unless_present = false @default = VividMash.new(self, default) @env_default = VividMash.new(self, {}) @role_default = VividMash.new(self, {}) @force_default = VividMash.new(self, {}) @normal = VividMash.new(self, normal) @override = VividMash.new(self, override) @role_override = VividMash.new(self, {}) @env_override = VividMash.new(self, {}) @force_override = VividMash.new(self, {}) @automatic = VividMash.new(self, automatic) @merged_attributes = nil @combined_override = nil @combined_default = nil end # Debug what's going on with an attribute. +args+ is a path spec to the # attribute you're interested in. For example, to debug where the value # of `node[:network][:default_interface]` is coming from, use: # debug_value(:network, :default_interface). # The return value is an Array of Arrays. The first element is # `["set_unless_enabled?", Boolean]`, which describes whether the # attribute collection is in "set_unless" mode. The rest of the Arrays # are pairs of `["precedence_level", value]`, where precedence level is # the component, such as role default, normal, etc. and value is the # attribute value set at that precedence level. If there is no value at # that precedence level, +value+ will be the symbol +:not_present+. def debug_value(*args) components = COMPONENTS.map do |component| ivar = instance_variable_get(component) value = args.inject(ivar) do |so_far, key| if so_far == :not_present :not_present elsif so_far.has_key?(key) so_far[key] else :not_present end end [component.to_s.sub(/^@/,""), value] end [["set_unless_enabled?", @set_unless_present]] + components end # Enables or disables `||=`-like attribute setting. See, e.g., Node#set_unless def set_unless_value_present=(setting) @set_unless_present = setting end # Clears merged_attributes, which will cause it to be recomputed on the # next access. def reset_cache @merged_attributes = nil @combined_default = nil @combined_override = nil @set_unless_present = false end alias :reset :reset_cache # Set the cookbook level default attribute component to +new_data+. def default=(new_data) reset @default = VividMash.new(self, new_data) end # Set the role level default attribute component to +new_data+ def role_default=(new_data) reset @role_default = VividMash.new(self, new_data) end # Set the environment level default attribute component to +new_data+ def env_default=(new_data) reset @env_default = VividMash.new(self, new_data) end # Set the force_default (+default!+) level attributes to +new_data+ def force_default=(new_data) reset @force_default = VividMash.new(self, new_data) end # Set the normal level attribute component to +new_data+ def normal=(new_data) reset @normal = VividMash.new(self, new_data) end # Set the cookbook level override attribute component to +new_data+ def override=(new_data) reset @override = VividMash.new(self, new_data) end # Set the role level override attribute component to +new_data+ def role_override=(new_data) reset @role_override = VividMash.new(self, new_data) end # Set the environment level override attribute component to +new_data+ def env_override=(new_data) reset @env_override = VividMash.new(self, new_data) end def force_override=(new_data) reset @force_override = VividMash.new(self, new_data) end def automatic=(new_data) reset @automatic = VividMash.new(self, new_data) end def merged_attributes @merged_attributes ||= begin components = [merge_defaults, @normal, merge_overrides, @automatic] resolved_attrs = components.inject(Mash.new) do |merged, component| Chef::Mixin::DeepMerge.hash_only_merge(merged, component) end immutablize(resolved_attrs) end end def combined_override @combined_override ||= immutablize(merge_overrides) end def combined_default @combined_default ||= immutablize(merge_defaults) end def [](key) merged_attributes[key] end def []=(key, value) merged_attributes[key] = value end def has_key?(key) COMPONENTS.any? do |component_ivar| instance_variable_get(component_ivar).has_key?(key) end end alias :attribute? :has_key? alias :member? :has_key? alias :include? :has_key? alias :key? :has_key? alias :each_attribute :each def method_missing(symbol, *args) if args.empty? if key?(symbol) self[symbol] else raise NoMethodError, "Undefined method or attribute `#{symbol}' on `node'" end elsif symbol.to_s =~ /=$/ key_to_set = symbol.to_s[/^(.+)=$/, 1] self[key_to_set] = (args.length == 1 ? args[0] : args) else raise NoMethodError, "Undefined node attribute or method `#{symbol}' on `node'" end end def inspect "#<#{self.class} " << (COMPONENTS + [:@merged_attributes, :@properties]).map{|iv| "#{iv}=#{instance_variable_get(iv).inspect}" }.join(', ') << ">" end def set_unless? @set_unless_present end private def merge_defaults DEFAULT_COMPONENTS.inject(Mash.new) do |merged, component_ivar| component_value = instance_variable_get(component_ivar) Chef::Mixin::DeepMerge.merge(merged, component_value) end end def merge_overrides OVERRIDE_COMPONENTS.inject(Mash.new) do |merged, component_ivar| component_value = instance_variable_get(component_ivar) Chef::Mixin::DeepMerge.merge(merged, component_value) end end end end end chef-11.8.2/lib/chef.rb0000644000004100000410000000224312254362222014541 0ustar www-datawww-data# # Author:: Adam Jacob () # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'chef/version' require 'chef/nil_argument' require 'chef/mash' require 'chef/exceptions' require 'chef/log' require 'chef/config' require 'chef/providers' require 'chef/resources' require 'chef/shell_out' require 'chef/daemon' require 'chef/run_status' require 'chef/handler' require 'chef/handler/json_file' require 'chef/monkey_patches/tempfile' require 'chef/monkey_patches/string' require 'chef/monkey_patches/numeric' require 'chef/monkey_patches/object' require 'chef/monkey_patches/file' chef-11.8.2/metadata.yml0000644000004100000410000020553412254362222015054 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: chef version: !ruby/object:Gem::Version version: 11.8.2 prerelease: platform: ruby authors: - Adam Jacob autorequire: bindir: bin cert_chain: [] date: 2013-12-03 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: mixlib-config requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '2.0' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '2.0' - !ruby/object:Gem::Dependency name: mixlib-cli requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.3' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.3' - !ruby/object:Gem::Dependency name: mixlib-log requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.3' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.3' - !ruby/object:Gem::Dependency name: mixlib-authentication requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.3' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.3' - !ruby/object:Gem::Dependency name: mixlib-shellout requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.2' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.2' - !ruby/object:Gem::Dependency name: ohai requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '6.0' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '6.0' - !ruby/object:Gem::Dependency name: rest-client requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 1.0.4 - - < - !ruby/object:Gem::Version version: 1.7.0 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 1.0.4 - - < - !ruby/object:Gem::Version version: 1.7.0 - !ruby/object:Gem::Dependency name: mime-types requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.16' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.16' - !ruby/object:Gem::Dependency name: json requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 1.4.4 - - <= - !ruby/object:Gem::Version version: 1.7.7 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 1.4.4 - - <= - !ruby/object:Gem::Version version: 1.7.7 - !ruby/object:Gem::Dependency name: yajl-ruby requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.1' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.1' - !ruby/object:Gem::Dependency name: net-ssh requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '2.6' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '2.6' - !ruby/object:Gem::Dependency name: net-ssh-multi requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: 1.1.0 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: 1.1.0 - !ruby/object:Gem::Dependency name: highline requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.6' - - ! '>=' - !ruby/object:Gem::Version version: 1.6.9 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.6' - - ! '>=' - !ruby/object:Gem::Version version: 1.6.9 - !ruby/object:Gem::Dependency name: erubis requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '2.7' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '2.7' - !ruby/object:Gem::Dependency name: diff-lcs requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.2' - - ! '>=' - !ruby/object:Gem::Version version: 1.2.4 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.2' - - ! '>=' - !ruby/object:Gem::Version version: 1.2.4 - !ruby/object:Gem::Dependency name: chef-zero requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.6' - - ! '>=' - !ruby/object:Gem::Version version: 1.6.2 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.6' - - ! '>=' - !ruby/object:Gem::Version version: 1.6.2 - !ruby/object:Gem::Dependency name: puma requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.6' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.6' - !ruby/object:Gem::Dependency name: pry requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '0.9' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '0.9' - !ruby/object:Gem::Dependency name: rdoc requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: sdoc requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: rake requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: rack requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: rspec_junit_formatter requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: rspec-core requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: 2.13.0 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: 2.13.0 - !ruby/object:Gem::Dependency name: rspec-expectations requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: 2.13.0 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: 2.13.0 - !ruby/object:Gem::Dependency name: rspec-mocks requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: 2.13.0 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: 2.13.0 description: A systems integration framework, built to bring the benefits of configuration management to your entire infrastructure. email: adam@opscode.com executables: - chef-client - chef-solo - knife - chef-shell - shef - chef-apply - chef-service-manager extensions: [] extra_rdoc_files: - README.md - CONTRIBUTING.md - LICENSE files: - Rakefile - LICENSE - README.md - CONTRIBUTING.md - distro/arch/etc/conf.d/chef-client.conf - distro/arch/etc/conf.d/chef-expander.conf - distro/arch/etc/conf.d/chef-server-webui.conf - distro/arch/etc/conf.d/chef-server.conf - distro/arch/etc/conf.d/chef-solr.conf - distro/arch/etc/rc.d/chef-client - distro/arch/etc/rc.d/chef-expander - distro/arch/etc/rc.d/chef-server - distro/arch/etc/rc.d/chef-server-webui - distro/arch/etc/rc.d/chef-solr - distro/common/html/chef-client.8.html - distro/common/html/chef-expander.8.html - distro/common/html/chef-expanderctl.8.html - distro/common/html/chef-server-webui.8.html - distro/common/html/chef-server.8.html - distro/common/html/chef-shell.1.html - distro/common/html/chef-solo.8.html - distro/common/html/chef-solr.8.html - distro/common/html/knife-bootstrap.1.html - distro/common/html/knife-client.1.html - distro/common/html/knife-configure.1.html - distro/common/html/knife-cookbook-site.1.html - distro/common/html/knife-cookbook.1.html - distro/common/html/knife-data-bag.1.html - distro/common/html/knife-environment.1.html - distro/common/html/knife-exec.1.html - distro/common/html/knife-index.1.html - distro/common/html/knife-node.1.html - distro/common/html/knife-role.1.html - distro/common/html/knife-search.1.html - distro/common/html/knife-ssh.1.html - distro/common/html/knife-status.1.html - distro/common/html/knife-tag.1.html - distro/common/html/knife.1.html - distro/common/man/man1/chef-shell.1 - distro/common/man/man1/knife-bootstrap.1 - distro/common/man/man1/knife-client.1 - distro/common/man/man1/knife-configure.1 - distro/common/man/man1/knife-cookbook-site.1 - distro/common/man/man1/knife-cookbook.1 - distro/common/man/man1/knife-data-bag.1 - distro/common/man/man1/knife-delete.1 - distro/common/man/man1/knife-deps.1 - distro/common/man/man1/knife-diff.1 - distro/common/man/man1/knife-download.1 - distro/common/man/man1/knife-edit.1 - distro/common/man/man1/knife-environment.1 - distro/common/man/man1/knife-exec.1 - distro/common/man/man1/knife-index-rebuild.1 - distro/common/man/man1/knife-list.1 - distro/common/man/man1/knife-node.1 - distro/common/man/man1/knife-raw.1 - distro/common/man/man1/knife-recipe-list.1 - distro/common/man/man1/knife-role.1 - distro/common/man/man1/knife-search.1 - distro/common/man/man1/knife-show.1 - distro/common/man/man1/knife-ssh.1 - distro/common/man/man1/knife-status.1 - distro/common/man/man1/knife-tag.1 - distro/common/man/man1/knife-upload.1 - distro/common/man/man1/knife-user.1 - distro/common/man/man1/knife-xargs.1 - distro/common/man/man1/knife.1 - distro/common/man/man1/README.md - distro/common/man/man8/chef-client.8 - distro/common/man/man8/chef-solo.8 - distro/common/markdown/man1/chef-shell.mkd - distro/common/markdown/man1/knife-bootstrap.mkd - distro/common/markdown/man1/knife-client.mkd - distro/common/markdown/man1/knife-configure.mkd - distro/common/markdown/man1/knife-cookbook-site.mkd - distro/common/markdown/man1/knife-cookbook.mkd - distro/common/markdown/man1/knife-data-bag.mkd - distro/common/markdown/man1/knife-environment.mkd - distro/common/markdown/man1/knife-exec.mkd - distro/common/markdown/man1/knife-index.mkd - distro/common/markdown/man1/knife-node.mkd - distro/common/markdown/man1/knife-role.mkd - distro/common/markdown/man1/knife-search.mkd - distro/common/markdown/man1/knife-ssh.mkd - distro/common/markdown/man1/knife-status.mkd - distro/common/markdown/man1/knife-tag.mkd - distro/common/markdown/man1/knife.mkd - distro/common/markdown/man8/chef-client.mkd - distro/common/markdown/man8/chef-expander.mkd - distro/common/markdown/man8/chef-expanderctl.mkd - distro/common/markdown/man8/chef-server-webui.mkd - distro/common/markdown/man8/chef-server.mkd - distro/common/markdown/man8/chef-solo.mkd - distro/common/markdown/man8/chef-solr.mkd - distro/common/markdown/README - distro/debian/etc/default/chef-client - distro/debian/etc/default/chef-expander - distro/debian/etc/default/chef-server - distro/debian/etc/default/chef-server-webui - distro/debian/etc/default/chef-solr - distro/debian/etc/init/chef-client.conf - distro/debian/etc/init/chef-expander.conf - distro/debian/etc/init/chef-server-webui.conf - distro/debian/etc/init/chef-server.conf - distro/debian/etc/init/chef-solr.conf - distro/debian/etc/init.d/chef-client - distro/debian/etc/init.d/chef-expander - distro/debian/etc/init.d/chef-server - distro/debian/etc/init.d/chef-server-webui - distro/debian/etc/init.d/chef-solr - distro/README - distro/redhat/etc/init.d/chef-client - distro/redhat/etc/init.d/chef-expander - distro/redhat/etc/init.d/chef-server - distro/redhat/etc/init.d/chef-server-webui - distro/redhat/etc/init.d/chef-solr - distro/redhat/etc/logrotate.d/chef-client - distro/redhat/etc/logrotate.d/chef-expander - distro/redhat/etc/logrotate.d/chef-server - distro/redhat/etc/logrotate.d/chef-server-webui - distro/redhat/etc/logrotate.d/chef-solr - distro/redhat/etc/sysconfig/chef-client - distro/redhat/etc/sysconfig/chef-expander - distro/redhat/etc/sysconfig/chef-server - distro/redhat/etc/sysconfig/chef-server-webui - distro/redhat/etc/sysconfig/chef-solr - distro/windows/service_manager.rb - lib/chef/api_client/registration.rb - lib/chef/api_client.rb - lib/chef/application/agent.rb - lib/chef/application/apply.rb - lib/chef/application/client.rb - lib/chef/application/knife.rb - lib/chef/application/solo.rb - lib/chef/application/windows_service.rb - lib/chef/application/windows_service_manager.rb - lib/chef/application.rb - lib/chef/applications.rb - lib/chef/checksum/storage/filesystem.rb - lib/chef/checksum/storage.rb - lib/chef/chef_fs/chef_fs_data_store.rb - lib/chef/chef_fs/command_line.rb - lib/chef/chef_fs/config.rb - lib/chef/chef_fs/data_handler/acl_data_handler.rb - lib/chef/chef_fs/data_handler/client_data_handler.rb - lib/chef/chef_fs/data_handler/container_data_handler.rb - lib/chef/chef_fs/data_handler/cookbook_data_handler.rb - lib/chef/chef_fs/data_handler/data_bag_item_data_handler.rb - lib/chef/chef_fs/data_handler/data_handler_base.rb - lib/chef/chef_fs/data_handler/environment_data_handler.rb - lib/chef/chef_fs/data_handler/group_data_handler.rb - lib/chef/chef_fs/data_handler/node_data_handler.rb - lib/chef/chef_fs/data_handler/role_data_handler.rb - lib/chef/chef_fs/data_handler/user_data_handler.rb - lib/chef/chef_fs/file_pattern.rb - lib/chef/chef_fs/file_system/acl_dir.rb - lib/chef/chef_fs/file_system/acl_entry.rb - lib/chef/chef_fs/file_system/acls_dir.rb - lib/chef/chef_fs/file_system/already_exists_error.rb - lib/chef/chef_fs/file_system/base_fs_dir.rb - lib/chef/chef_fs/file_system/base_fs_object.rb - lib/chef/chef_fs/file_system/chef_repository_file_system_acls_dir.rb - lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir.rb - lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry.rb - lib/chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir.rb - lib/chef/chef_fs/file_system/chef_repository_file_system_data_bags_dir.rb - lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb - lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb - lib/chef/chef_fs/file_system/chef_server_root_dir.rb - lib/chef/chef_fs/file_system/cookbook_dir.rb - lib/chef/chef_fs/file_system/cookbook_file.rb - lib/chef/chef_fs/file_system/cookbook_frozen_error.rb - lib/chef/chef_fs/file_system/cookbook_subdir.rb - lib/chef/chef_fs/file_system/cookbooks_acl_dir.rb - lib/chef/chef_fs/file_system/cookbooks_dir.rb - lib/chef/chef_fs/file_system/data_bag_dir.rb - lib/chef/chef_fs/file_system/data_bags_dir.rb - lib/chef/chef_fs/file_system/default_environment_cannot_be_modified_error.rb - lib/chef/chef_fs/file_system/environments_dir.rb - lib/chef/chef_fs/file_system/file_system_entry.rb - lib/chef/chef_fs/file_system/file_system_error.rb - lib/chef/chef_fs/file_system/file_system_root_dir.rb - lib/chef/chef_fs/file_system/memory_dir.rb - lib/chef/chef_fs/file_system/memory_file.rb - lib/chef/chef_fs/file_system/memory_root.rb - lib/chef/chef_fs/file_system/multiplexed_dir.rb - lib/chef/chef_fs/file_system/must_delete_recursively_error.rb - lib/chef/chef_fs/file_system/nodes_dir.rb - lib/chef/chef_fs/file_system/nonexistent_fs_object.rb - lib/chef/chef_fs/file_system/not_found_error.rb - lib/chef/chef_fs/file_system/operation_failed_error.rb - lib/chef/chef_fs/file_system/operation_not_allowed_error.rb - lib/chef/chef_fs/file_system/rest_list_dir.rb - lib/chef/chef_fs/file_system/rest_list_entry.rb - lib/chef/chef_fs/file_system.rb - lib/chef/chef_fs/knife.rb - lib/chef/chef_fs/parallelizer.rb - lib/chef/chef_fs/path_utils.rb - lib/chef/chef_fs.rb - lib/chef/client.rb - lib/chef/config.rb - lib/chef/config_fetcher.rb - lib/chef/cookbook/chefignore.rb - lib/chef/cookbook/cookbook_collection.rb - lib/chef/cookbook/cookbook_version_loader.rb - lib/chef/cookbook/file_system_file_vendor.rb - lib/chef/cookbook/file_vendor.rb - lib/chef/cookbook/metadata.rb - lib/chef/cookbook/remote_file_vendor.rb - lib/chef/cookbook/synchronizer.rb - lib/chef/cookbook/syntax_check.rb - lib/chef/cookbook_loader.rb - lib/chef/cookbook_site_streaming_uploader.rb - lib/chef/cookbook_uploader.rb - lib/chef/cookbook_version.rb - lib/chef/daemon.rb - lib/chef/data_bag.rb - lib/chef/data_bag_item.rb - lib/chef/deprecation/mixin/template.rb - lib/chef/deprecation/provider/cookbook_file.rb - lib/chef/deprecation/provider/file.rb - lib/chef/deprecation/provider/remote_file.rb - lib/chef/deprecation/provider/template.rb - lib/chef/deprecation/warnings.rb - lib/chef/digester.rb - lib/chef/dsl/data_query.rb - lib/chef/dsl/include_attribute.rb - lib/chef/dsl/include_recipe.rb - lib/chef/dsl/platform_introspection.rb - lib/chef/dsl/recipe.rb - lib/chef/dsl/registry_helper.rb - lib/chef/dsl.rb - lib/chef/encrypted_data_bag_item.rb - lib/chef/environment.rb - lib/chef/event_dispatch/base.rb - lib/chef/event_dispatch/dispatcher.rb - lib/chef/exceptions.rb - lib/chef/file_access_control/unix.rb - lib/chef/file_access_control/windows.rb - lib/chef/file_access_control.rb - lib/chef/file_cache.rb - lib/chef/file_content_management/content_base.rb - lib/chef/file_content_management/deploy/cp.rb - lib/chef/file_content_management/deploy/mv_unix.rb - lib/chef/file_content_management/deploy/mv_windows.rb - lib/chef/file_content_management/deploy.rb - lib/chef/file_content_management/tempfile.rb - lib/chef/formatters/base.rb - lib/chef/formatters/doc.rb - lib/chef/formatters/error_descriptor.rb - lib/chef/formatters/error_inspectors/api_error_formatting.rb - lib/chef/formatters/error_inspectors/compile_error_inspector.rb - lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb - lib/chef/formatters/error_inspectors/cookbook_sync_error_inspector.rb - lib/chef/formatters/error_inspectors/node_load_error_inspector.rb - lib/chef/formatters/error_inspectors/registration_error_inspector.rb - lib/chef/formatters/error_inspectors/resource_failure_inspector.rb - lib/chef/formatters/error_inspectors/run_list_expansion_error_inspector.rb - lib/chef/formatters/error_inspectors.rb - lib/chef/formatters/error_mapper.rb - lib/chef/formatters/minimal.rb - lib/chef/handler/error_report.rb - lib/chef/handler/json_file.rb - lib/chef/handler.rb - lib/chef/http/auth_credentials.rb - lib/chef/http/authenticator.rb - lib/chef/http/basic_client.rb - lib/chef/http/cookie_jar.rb - lib/chef/http/cookie_manager.rb - lib/chef/http/decompressor.rb - lib/chef/http/http_request.rb - lib/chef/http/json_input.rb - lib/chef/http/json_output.rb - lib/chef/http/json_to_model_output.rb - lib/chef/http/simple.rb - lib/chef/http/ssl_policies.rb - lib/chef/http.rb - lib/chef/json_compat.rb - lib/chef/knife/bootstrap/archlinux-gems.erb - lib/chef/knife/bootstrap/centos5-gems.erb - lib/chef/knife/bootstrap/chef-full.erb - lib/chef/knife/bootstrap/fedora13-gems.erb - lib/chef/knife/bootstrap/ubuntu10.04-apt.erb - lib/chef/knife/bootstrap/ubuntu10.04-gems.erb - lib/chef/knife/bootstrap/ubuntu12.04-gems.erb - lib/chef/knife/bootstrap.rb - lib/chef/knife/client_bulk_delete.rb - lib/chef/knife/client_create.rb - lib/chef/knife/client_delete.rb - lib/chef/knife/client_edit.rb - lib/chef/knife/client_list.rb - lib/chef/knife/client_reregister.rb - lib/chef/knife/client_show.rb - lib/chef/knife/configure.rb - lib/chef/knife/configure_client.rb - lib/chef/knife/cookbook_bulk_delete.rb - lib/chef/knife/cookbook_create.rb - lib/chef/knife/cookbook_delete.rb - lib/chef/knife/cookbook_download.rb - lib/chef/knife/cookbook_list.rb - lib/chef/knife/cookbook_metadata.rb - lib/chef/knife/cookbook_metadata_from_file.rb - lib/chef/knife/cookbook_show.rb - lib/chef/knife/cookbook_site_download.rb - lib/chef/knife/cookbook_site_install.rb - lib/chef/knife/cookbook_site_list.rb - lib/chef/knife/cookbook_site_search.rb - lib/chef/knife/cookbook_site_share.rb - lib/chef/knife/cookbook_site_show.rb - lib/chef/knife/cookbook_site_unshare.rb - lib/chef/knife/cookbook_site_vendor.rb - lib/chef/knife/cookbook_test.rb - lib/chef/knife/cookbook_upload.rb - lib/chef/knife/core/bootstrap_context.rb - lib/chef/knife/core/cookbook_scm_repo.rb - lib/chef/knife/core/generic_presenter.rb - lib/chef/knife/core/node_editor.rb - lib/chef/knife/core/node_presenter.rb - lib/chef/knife/core/object_loader.rb - lib/chef/knife/core/subcommand_loader.rb - lib/chef/knife/core/text_formatter.rb - lib/chef/knife/core/ui.rb - lib/chef/knife/data_bag_create.rb - lib/chef/knife/data_bag_delete.rb - lib/chef/knife/data_bag_edit.rb - lib/chef/knife/data_bag_from_file.rb - lib/chef/knife/data_bag_list.rb - lib/chef/knife/data_bag_show.rb - lib/chef/knife/delete.rb - lib/chef/knife/deps.rb - lib/chef/knife/diff.rb - lib/chef/knife/download.rb - lib/chef/knife/edit.rb - lib/chef/knife/environment_create.rb - lib/chef/knife/environment_delete.rb - lib/chef/knife/environment_edit.rb - lib/chef/knife/environment_from_file.rb - lib/chef/knife/environment_list.rb - lib/chef/knife/environment_show.rb - lib/chef/knife/exec.rb - lib/chef/knife/help.rb - lib/chef/knife/help_topics.rb - lib/chef/knife/index_rebuild.rb - lib/chef/knife/list.rb - lib/chef/knife/node_bulk_delete.rb - lib/chef/knife/node_create.rb - lib/chef/knife/node_delete.rb - lib/chef/knife/node_edit.rb - lib/chef/knife/node_from_file.rb - lib/chef/knife/node_list.rb - lib/chef/knife/node_run_list_add.rb - lib/chef/knife/node_run_list_remove.rb - lib/chef/knife/node_run_list_set.rb - lib/chef/knife/node_show.rb - lib/chef/knife/raw.rb - lib/chef/knife/recipe_list.rb - lib/chef/knife/role_bulk_delete.rb - lib/chef/knife/role_create.rb - lib/chef/knife/role_delete.rb - lib/chef/knife/role_edit.rb - lib/chef/knife/role_from_file.rb - lib/chef/knife/role_list.rb - lib/chef/knife/role_show.rb - lib/chef/knife/search.rb - lib/chef/knife/show.rb - lib/chef/knife/ssh.rb - lib/chef/knife/status.rb - lib/chef/knife/tag_create.rb - lib/chef/knife/tag_delete.rb - lib/chef/knife/tag_list.rb - lib/chef/knife/upload.rb - lib/chef/knife/user_create.rb - lib/chef/knife/user_delete.rb - lib/chef/knife/user_edit.rb - lib/chef/knife/user_list.rb - lib/chef/knife/user_reregister.rb - lib/chef/knife/user_show.rb - lib/chef/knife/xargs.rb - lib/chef/knife.rb - lib/chef/log.rb - lib/chef/mash.rb - lib/chef/mixin/checksum.rb - lib/chef/mixin/command/unix.rb - lib/chef/mixin/command/windows.rb - lib/chef/mixin/command.rb - lib/chef/mixin/convert_to_class_name.rb - lib/chef/mixin/create_path.rb - lib/chef/mixin/deep_merge.rb - lib/chef/mixin/deprecation.rb - lib/chef/mixin/enforce_ownership_and_permissions.rb - lib/chef/mixin/file_class.rb - lib/chef/mixin/from_file.rb - lib/chef/mixin/get_source_from_package.rb - lib/chef/mixin/language.rb - lib/chef/mixin/language_include_attribute.rb - lib/chef/mixin/language_include_recipe.rb - lib/chef/mixin/params_validate.rb - lib/chef/mixin/path_sanity.rb - lib/chef/mixin/recipe_definition_dsl_core.rb - lib/chef/mixin/securable.rb - lib/chef/mixin/shell_out.rb - lib/chef/mixin/template.rb - lib/chef/mixin/why_run.rb - lib/chef/mixin/windows_architecture_helper.rb - lib/chef/mixin/xml_escape.rb - lib/chef/mixins.rb - lib/chef/monkey_patches/file.rb - lib/chef/monkey_patches/fileutils.rb - lib/chef/monkey_patches/net-ssh-multi.rb - lib/chef/monkey_patches/net_http.rb - lib/chef/monkey_patches/numeric.rb - lib/chef/monkey_patches/object.rb - lib/chef/monkey_patches/regexp.rb - lib/chef/monkey_patches/securerandom.rb - lib/chef/monkey_patches/string.rb - lib/chef/monkey_patches/tempfile.rb - lib/chef/monologger.rb - lib/chef/nil_argument.rb - lib/chef/node/attribute.rb - lib/chef/node/attribute_collections.rb - lib/chef/node/immutable_collections.rb - lib/chef/node.rb - lib/chef/platform/provider_mapping.rb - lib/chef/platform/query_helpers.rb - lib/chef/platform.rb - lib/chef/provider/batch.rb - lib/chef/provider/breakpoint.rb - lib/chef/provider/cookbook_file/content.rb - lib/chef/provider/cookbook_file.rb - lib/chef/provider/cron/aix.rb - lib/chef/provider/cron/solaris.rb - lib/chef/provider/cron/unix.rb - lib/chef/provider/cron.rb - lib/chef/provider/deploy/revision.rb - lib/chef/provider/deploy/timestamped.rb - lib/chef/provider/deploy.rb - lib/chef/provider/directory.rb - lib/chef/provider/env/windows.rb - lib/chef/provider/env.rb - lib/chef/provider/erl_call.rb - lib/chef/provider/execute.rb - lib/chef/provider/file/content.rb - lib/chef/provider/file.rb - lib/chef/provider/git.rb - lib/chef/provider/group/aix.rb - lib/chef/provider/group/dscl.rb - lib/chef/provider/group/gpasswd.rb - lib/chef/provider/group/groupadd.rb - lib/chef/provider/group/groupmod.rb - lib/chef/provider/group/pw.rb - lib/chef/provider/group/suse.rb - lib/chef/provider/group/usermod.rb - lib/chef/provider/group/windows.rb - lib/chef/provider/group.rb - lib/chef/provider/http_request.rb - lib/chef/provider/ifconfig/aix.rb - lib/chef/provider/ifconfig/debian.rb - lib/chef/provider/ifconfig/redhat.rb - lib/chef/provider/ifconfig.rb - lib/chef/provider/link.rb - lib/chef/provider/log.rb - lib/chef/provider/lwrp_base.rb - lib/chef/provider/mdadm.rb - lib/chef/provider/mount/aix.rb - lib/chef/provider/mount/mount.rb - lib/chef/provider/mount/windows.rb - lib/chef/provider/mount.rb - lib/chef/provider/ohai.rb - lib/chef/provider/package/aix.rb - lib/chef/provider/package/apt.rb - lib/chef/provider/package/dpkg.rb - lib/chef/provider/package/easy_install.rb - lib/chef/provider/package/freebsd.rb - lib/chef/provider/package/ips.rb - lib/chef/provider/package/macports.rb - lib/chef/provider/package/pacman.rb - lib/chef/provider/package/portage.rb - lib/chef/provider/package/rpm.rb - lib/chef/provider/package/rubygems.rb - lib/chef/provider/package/smartos.rb - lib/chef/provider/package/solaris.rb - lib/chef/provider/package/yum-dump.py - lib/chef/provider/package/yum.rb - lib/chef/provider/package/zypper.rb - lib/chef/provider/package.rb - lib/chef/provider/powershell_script.rb - lib/chef/provider/registry_key.rb - lib/chef/provider/remote_directory.rb - lib/chef/provider/remote_file/cache_control_data.rb - lib/chef/provider/remote_file/content.rb - lib/chef/provider/remote_file/fetcher.rb - lib/chef/provider/remote_file/ftp.rb - lib/chef/provider/remote_file/http.rb - lib/chef/provider/remote_file/local_file.rb - lib/chef/provider/remote_file.rb - lib/chef/provider/resource_update.rb - lib/chef/provider/route.rb - lib/chef/provider/ruby_block.rb - lib/chef/provider/script.rb - lib/chef/provider/service/arch.rb - lib/chef/provider/service/debian.rb - lib/chef/provider/service/freebsd.rb - lib/chef/provider/service/gentoo.rb - lib/chef/provider/service/init.rb - lib/chef/provider/service/insserv.rb - lib/chef/provider/service/invokercd.rb - lib/chef/provider/service/macosx.rb - lib/chef/provider/service/redhat.rb - lib/chef/provider/service/simple.rb - lib/chef/provider/service/solaris.rb - lib/chef/provider/service/systemd.rb - lib/chef/provider/service/upstart.rb - lib/chef/provider/service/windows.rb - lib/chef/provider/service.rb - lib/chef/provider/subversion.rb - lib/chef/provider/template/content.rb - lib/chef/provider/template.rb - lib/chef/provider/template_finder.rb - lib/chef/provider/user/dscl.rb - lib/chef/provider/user/pw.rb - lib/chef/provider/user/solaris.rb - lib/chef/provider/user/useradd.rb - lib/chef/provider/user/windows.rb - lib/chef/provider/user.rb - lib/chef/provider/windows_script.rb - lib/chef/provider.rb - lib/chef/providers.rb - lib/chef/recipe.rb - lib/chef/reserved_names.rb - lib/chef/resource/apt_package.rb - lib/chef/resource/bash.rb - lib/chef/resource/batch.rb - lib/chef/resource/bff_package.rb - lib/chef/resource/breakpoint.rb - lib/chef/resource/chef_gem.rb - lib/chef/resource/conditional.rb - lib/chef/resource/conditional_action_not_nothing.rb - lib/chef/resource/cookbook_file.rb - lib/chef/resource/cron.rb - lib/chef/resource/csh.rb - lib/chef/resource/deploy.rb - lib/chef/resource/deploy_revision.rb - lib/chef/resource/directory.rb - lib/chef/resource/dpkg_package.rb - lib/chef/resource/easy_install_package.rb - lib/chef/resource/env.rb - lib/chef/resource/erl_call.rb - lib/chef/resource/execute.rb - lib/chef/resource/file.rb - lib/chef/resource/freebsd_package.rb - lib/chef/resource/gem_package.rb - lib/chef/resource/git.rb - lib/chef/resource/group.rb - lib/chef/resource/http_request.rb - lib/chef/resource/ifconfig.rb - lib/chef/resource/ips_package.rb - lib/chef/resource/link.rb - lib/chef/resource/log.rb - lib/chef/resource/lwrp_base.rb - lib/chef/resource/macports_package.rb - lib/chef/resource/mdadm.rb - lib/chef/resource/mount.rb - lib/chef/resource/ohai.rb - lib/chef/resource/package.rb - lib/chef/resource/pacman_package.rb - lib/chef/resource/perl.rb - lib/chef/resource/portage_package.rb - lib/chef/resource/powershell_script.rb - lib/chef/resource/python.rb - lib/chef/resource/registry_key.rb - lib/chef/resource/remote_directory.rb - lib/chef/resource/remote_file.rb - lib/chef/resource/route.rb - lib/chef/resource/rpm_package.rb - lib/chef/resource/ruby.rb - lib/chef/resource/ruby_block.rb - lib/chef/resource/scm.rb - lib/chef/resource/script.rb - lib/chef/resource/service.rb - lib/chef/resource/smartos_package.rb - lib/chef/resource/solaris_package.rb - lib/chef/resource/subversion.rb - lib/chef/resource/template.rb - lib/chef/resource/timestamped_deploy.rb - lib/chef/resource/user.rb - lib/chef/resource/windows_script.rb - lib/chef/resource/yum_package.rb - lib/chef/resource.rb - lib/chef/resource_collection/stepable_iterator.rb - lib/chef/resource_collection.rb - lib/chef/resource_definition.rb - lib/chef/resource_definition_list.rb - lib/chef/resource_platform_map.rb - lib/chef/resource_reporter.rb - lib/chef/resources.rb - lib/chef/rest.rb - lib/chef/role.rb - lib/chef/run_context/cookbook_compiler.rb - lib/chef/run_context.rb - lib/chef/run_list/run_list_expansion.rb - lib/chef/run_list/run_list_item.rb - lib/chef/run_list/versioned_recipe_list.rb - lib/chef/run_list.rb - lib/chef/run_lock.rb - lib/chef/run_status.rb - lib/chef/runner.rb - lib/chef/sandbox.rb - lib/chef/scan_access_control.rb - lib/chef/search/query.rb - lib/chef/server_api.rb - lib/chef/shef/ext.rb - lib/chef/shell/ext.rb - lib/chef/shell/model_wrapper.rb - lib/chef/shell/shell_rest.rb - lib/chef/shell/shell_session.rb - lib/chef/shell.rb - lib/chef/shell_out.rb - lib/chef/streaming_cookbook_uploader.rb - lib/chef/tasks/chef_repo.rake - lib/chef/user.rb - lib/chef/util/backup.rb - lib/chef/util/diff.rb - lib/chef/util/file_edit.rb - lib/chef/util/selinux.rb - lib/chef/util/windows/net_group.rb - lib/chef/util/windows/net_use.rb - lib/chef/util/windows/net_user.rb - lib/chef/util/windows/volume.rb - lib/chef/util/windows.rb - lib/chef/version/platform.rb - lib/chef/version.rb - lib/chef/version_class.rb - lib/chef/version_constraint/platform.rb - lib/chef/version_constraint.rb - lib/chef/win32/api/error.rb - lib/chef/win32/api/file.rb - lib/chef/win32/api/memory.rb - lib/chef/win32/api/process.rb - lib/chef/win32/api/psapi.rb - lib/chef/win32/api/security.rb - lib/chef/win32/api/synchronization.rb - lib/chef/win32/api/system.rb - lib/chef/win32/api/unicode.rb - lib/chef/win32/api.rb - lib/chef/win32/error.rb - lib/chef/win32/file/info.rb - lib/chef/win32/file.rb - lib/chef/win32/handle.rb - lib/chef/win32/memory.rb - lib/chef/win32/mutex.rb - lib/chef/win32/process.rb - lib/chef/win32/registry.rb - lib/chef/win32/security/ace.rb - lib/chef/win32/security/acl.rb - lib/chef/win32/security/securable_object.rb - lib/chef/win32/security/security_descriptor.rb - lib/chef/win32/security/sid.rb - lib/chef/win32/security/token.rb - lib/chef/win32/security.rb - lib/chef/win32/unicode.rb - lib/chef/win32/version.rb - lib/chef.rb - tasks/rspec.rb - spec/data/apt/chef-integration-test-1.0/debian/changelog - spec/data/apt/chef-integration-test-1.0/debian/compat - spec/data/apt/chef-integration-test-1.0/debian/control - spec/data/apt/chef-integration-test-1.0/debian/copyright - spec/data/apt/chef-integration-test-1.0/debian/files - spec/data/apt/chef-integration-test-1.0/debian/rules - spec/data/apt/chef-integration-test-1.0/debian/source/format - spec/data/apt/chef-integration-test-1.1/debian/changelog - spec/data/apt/chef-integration-test-1.1/debian/compat - spec/data/apt/chef-integration-test-1.1/debian/control - spec/data/apt/chef-integration-test-1.1/debian/copyright - spec/data/apt/chef-integration-test-1.1/debian/files - spec/data/apt/chef-integration-test-1.1/debian/rules - spec/data/apt/chef-integration-test-1.1/debian/source/format - spec/data/apt/chef-integration-test_1.0-1_amd64.changes - spec/data/apt/chef-integration-test_1.0-1_amd64.deb - spec/data/apt/chef-integration-test_1.0.orig.tar.gz - spec/data/apt/chef-integration-test_1.1-1_amd64.changes - spec/data/apt/chef-integration-test_1.1-1_amd64.deb - spec/data/apt/chef-integration-test_1.1.orig.tar.gz - spec/data/apt/var/www/apt/conf/distributions - spec/data/apt/var/www/apt/conf/incoming - spec/data/apt/var/www/apt/conf/pulls - spec/data/apt/var/www/apt/db/checksums.db - spec/data/apt/var/www/apt/db/contents.cache.db - spec/data/apt/var/www/apt/db/packages.db - spec/data/apt/var/www/apt/db/references.db - spec/data/apt/var/www/apt/db/release.caches.db - spec/data/apt/var/www/apt/db/version - spec/data/apt/var/www/apt/dists/sid/main/binary-amd64/Packages - spec/data/apt/var/www/apt/dists/sid/main/binary-amd64/Packages.gz - spec/data/apt/var/www/apt/dists/sid/main/binary-amd64/Release - spec/data/apt/var/www/apt/dists/sid/main/binary-i386/Packages - spec/data/apt/var/www/apt/dists/sid/Release - spec/data/apt/var/www/apt/pool/main/c/chef-integration-test/chef-integration-test_1.0-1_amd64.deb - spec/data/apt/var/www/apt/pool/main/c/chef-integration-test/chef-integration-test_1.1-1_amd64.deb - spec/data/bad-config.rb - spec/data/big_json.json - spec/data/big_json_plus_one.json - spec/data/bootstrap/encrypted_data_bag_secret - spec/data/bootstrap/no_proxy.erb - spec/data/bootstrap/secret.erb - spec/data/bootstrap/test-hints.erb - spec/data/bootstrap/test.erb - spec/data/cb_version_cookbooks/tatft/attributes/default.rb - spec/data/cb_version_cookbooks/tatft/definitions/runit_service.rb - spec/data/cb_version_cookbooks/tatft/files/default/giant_blob.tgz - spec/data/cb_version_cookbooks/tatft/libraries/ownage.rb - spec/data/cb_version_cookbooks/tatft/providers/lwp.rb - spec/data/cb_version_cookbooks/tatft/README.rdoc - spec/data/cb_version_cookbooks/tatft/recipes/default.rb - spec/data/cb_version_cookbooks/tatft/resources/lwr.rb - spec/data/cb_version_cookbooks/tatft/templates/default/configuration.erb - spec/data/checksum/random.txt - spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-600hhz-0 - spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-6m8zdk-0 - spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ahd2gq-0 - spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-api8ux-0 - spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-b0r1m1-0 - spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-bfygsi-0 - spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-el14l6-0 - spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ivrl3y-0 - spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-kkbs85-0 - spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ory1ux-0 - spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-pgsq76-0 - spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ra8uim-0 - spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-t7k1g-0 - spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-t8g0sv-0 - spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ufy6g3-0 - spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-x2d6j9-0 - spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-xi0l6h-0 - spec/data/config.rb - spec/data/cookbooks/angrybash/recipes/default.rb - spec/data/cookbooks/apache2/files/default/apache2_module_conf_generate.pl - spec/data/cookbooks/apache2/recipes/default.rb - spec/data/cookbooks/borken/recipes/default.rb - spec/data/cookbooks/borken/templates/default/borken.erb - spec/data/cookbooks/chefignore - spec/data/cookbooks/ignorken/recipes/default.rb - spec/data/cookbooks/ignorken/recipes/ignoreme.rb - spec/data/cookbooks/java/files/default/java.response - spec/data/cookbooks/openldap/attributes/default.rb - spec/data/cookbooks/openldap/attributes/smokey.rb - spec/data/cookbooks/openldap/definitions/client.rb - spec/data/cookbooks/openldap/definitions/server.rb - spec/data/cookbooks/openldap/files/default/.dotfile - spec/data/cookbooks/openldap/files/default/.ssh/id_rsa - spec/data/cookbooks/openldap/files/default/remotedir/.a_dotdir/.a_dotfile_in_a_dotdir - spec/data/cookbooks/openldap/files/default/remotedir/remote_dir_file1.txt - spec/data/cookbooks/openldap/files/default/remotedir/remote_dir_file2.txt - spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/.a_dotfile - spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/remote_subdir_file1.txt - spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/remote_subdir_file2.txt - spec/data/cookbooks/openldap/files/default/remotedir/subdir_with_no_file_just_a_subsubdir/the_subsubdir/some_file.txt - spec/data/cookbooks/openldap/metadata.rb - spec/data/cookbooks/openldap/recipes/default.rb - spec/data/cookbooks/openldap/recipes/gigantor.rb - spec/data/cookbooks/openldap/recipes/one.rb - spec/data/cookbooks/openldap/templates/default/all_windows_line_endings.erb - spec/data/cookbooks/openldap/templates/default/helper_test.erb - spec/data/cookbooks/openldap/templates/default/helpers_via_partial_test.erb - spec/data/cookbooks/openldap/templates/default/no_windows_line_endings.erb - spec/data/cookbooks/openldap/templates/default/openldap_stuff.conf.erb - spec/data/cookbooks/openldap/templates/default/openldap_variable_stuff.conf.erb - spec/data/cookbooks/openldap/templates/default/some_windows_line_endings.erb - spec/data/cookbooks/openldap/templates/default/test.erb - spec/data/cookbooks/preseed/files/default/preseed-file.seed - spec/data/cookbooks/preseed/files/default/preseed-template.seed - spec/data/cookbooks/preseed/templates/default/preseed-template.seed - spec/data/definitions/test.rb - spec/data/environment-config.rb - spec/data/file-providers-method-snapshot-chef-11-4.json - spec/data/fileedit/blank - spec/data/fileedit/hosts - spec/data/gems/chef-integration-test-0.1.0.gem - spec/data/git_bundles/example-repo.gitbundle - spec/data/git_bundles/sinatra-test-app-with-callback-files.gitbundle - spec/data/git_bundles/sinatra-test-app-with-symlinks.gitbundle - spec/data/git_bundles/sinatra-test-app.gitbundle - spec/data/kitchen/chefignore - spec/data/kitchen/openldap/attributes/default.rb - spec/data/kitchen/openldap/attributes/robinson.rb - spec/data/kitchen/openldap/definitions/client.rb - spec/data/kitchen/openldap/definitions/drewbarrymore.rb - spec/data/kitchen/openldap/recipes/gigantor.rb - spec/data/kitchen/openldap/recipes/ignoreme.rb - spec/data/kitchen/openldap/recipes/woot.rb - spec/data/knife-home/.chef/plugins/knife/example_home_subcommand.rb - spec/data/knife-site-subcommands/plugins/knife/example_subcommand.rb - spec/data/knife_subcommand/test_explicit_category.rb - spec/data/knife_subcommand/test_name_mapping.rb - spec/data/knife_subcommand/test_yourself.rb - spec/data/lwrp/providers/buck_passer.rb - spec/data/lwrp/providers/buck_passer_2.rb - spec/data/lwrp/providers/embedded_resource_accesses_providers_scope.rb - spec/data/lwrp/providers/inline_compiler.rb - spec/data/lwrp/providers/monkey_name_printer.rb - spec/data/lwrp/providers/paint_drying_watcher.rb - spec/data/lwrp/providers/thumb_twiddler.rb - spec/data/lwrp/resources/bar.rb - spec/data/lwrp/resources/foo.rb - spec/data/lwrp/resources_with_default_attributes/nodeattr.rb - spec/data/lwrp_const_scoping/resources/conflict.rb - spec/data/lwrp_override/providers/buck_passer.rb - spec/data/lwrp_override/resources/foo.rb - spec/data/metadata/quick_start/metadata.rb - spec/data/nodes/default.rb - spec/data/nodes/test.example.com.rb - spec/data/nodes/test.rb - spec/data/null_config.rb - spec/data/object_loader/environments/test.json - spec/data/object_loader/environments/test.rb - spec/data/object_loader/environments/test_json_class.json - spec/data/object_loader/nodes/test.json - spec/data/object_loader/nodes/test.rb - spec/data/object_loader/nodes/test_json_class.json - spec/data/object_loader/roles/test.json - spec/data/object_loader/roles/test.rb - spec/data/object_loader/roles/test_json_class.json - spec/data/old_home_dir/my-dot-emacs - spec/data/old_home_dir/my-dot-vim - spec/data/partial_one.erb - spec/data/recipes/test.rb - spec/data/remote_directory_data/remote_dir_file.txt - spec/data/remote_directory_data/remote_subdirectory/remote_subdir_file.txt - spec/data/remote_file/nyan_cat.png - spec/data/remote_file/nyan_cat.png.gz - spec/data/run_context/cookbooks/circular-dep1/attributes/default.rb - spec/data/run_context/cookbooks/circular-dep1/definitions/circular_dep1_res.rb - spec/data/run_context/cookbooks/circular-dep1/libraries/lib.rb - spec/data/run_context/cookbooks/circular-dep1/metadata.rb - spec/data/run_context/cookbooks/circular-dep1/providers/provider.rb - spec/data/run_context/cookbooks/circular-dep1/recipes/default.rb - spec/data/run_context/cookbooks/circular-dep1/resources/resource.rb - spec/data/run_context/cookbooks/circular-dep2/attributes/default.rb - spec/data/run_context/cookbooks/circular-dep2/definitions/circular_dep2_res.rb - spec/data/run_context/cookbooks/circular-dep2/libraries/lib.rb - spec/data/run_context/cookbooks/circular-dep2/metadata.rb - spec/data/run_context/cookbooks/circular-dep2/providers/provider.rb - spec/data/run_context/cookbooks/circular-dep2/recipes/default.rb - spec/data/run_context/cookbooks/circular-dep2/resources/resource.rb - spec/data/run_context/cookbooks/dependency1/attributes/aa_first.rb - spec/data/run_context/cookbooks/dependency1/attributes/default.rb - spec/data/run_context/cookbooks/dependency1/attributes/zz_last.rb - spec/data/run_context/cookbooks/dependency1/definitions/dependency1_res.rb - spec/data/run_context/cookbooks/dependency1/libraries/lib.rb - spec/data/run_context/cookbooks/dependency1/providers/provider.rb - spec/data/run_context/cookbooks/dependency1/recipes/default.rb - spec/data/run_context/cookbooks/dependency1/resources/resource.rb - spec/data/run_context/cookbooks/dependency2/attributes/default.rb - spec/data/run_context/cookbooks/dependency2/definitions/dependency2_res.rb - spec/data/run_context/cookbooks/dependency2/libraries/lib.rb - spec/data/run_context/cookbooks/dependency2/providers/provider.rb - spec/data/run_context/cookbooks/dependency2/recipes/default.rb - spec/data/run_context/cookbooks/dependency2/resources/resource.rb - spec/data/run_context/cookbooks/no-default-attr/attributes/server.rb - spec/data/run_context/cookbooks/no-default-attr/definitions/no_default-attr_res.rb - spec/data/run_context/cookbooks/no-default-attr/providers/provider.rb - spec/data/run_context/cookbooks/no-default-attr/recipes/default.rb - spec/data/run_context/cookbooks/no-default-attr/resources/resource.rb - spec/data/run_context/cookbooks/test/attributes/default.rb - spec/data/run_context/cookbooks/test/attributes/george.rb - spec/data/run_context/cookbooks/test/definitions/new_animals.rb - spec/data/run_context/cookbooks/test/definitions/new_cat.rb - spec/data/run_context/cookbooks/test/definitions/test_res.rb - spec/data/run_context/cookbooks/test/providers/provider.rb - spec/data/run_context/cookbooks/test/recipes/default.rb - spec/data/run_context/cookbooks/test/recipes/one.rb - spec/data/run_context/cookbooks/test/recipes/two.rb - spec/data/run_context/cookbooks/test/resources/resource.rb - spec/data/run_context/cookbooks/test-with-circular-deps/attributes/default.rb - spec/data/run_context/cookbooks/test-with-circular-deps/definitions/test_with-circular-deps_res.rb - spec/data/run_context/cookbooks/test-with-circular-deps/libraries/lib.rb - spec/data/run_context/cookbooks/test-with-circular-deps/metadata.rb - spec/data/run_context/cookbooks/test-with-circular-deps/providers/provider.rb - spec/data/run_context/cookbooks/test-with-circular-deps/recipes/default.rb - spec/data/run_context/cookbooks/test-with-circular-deps/resources/resource.rb - spec/data/run_context/cookbooks/test-with-deps/attributes/default.rb - spec/data/run_context/cookbooks/test-with-deps/definitions/test_with-deps_res.rb - spec/data/run_context/cookbooks/test-with-deps/libraries/lib.rb - spec/data/run_context/cookbooks/test-with-deps/metadata.rb - spec/data/run_context/cookbooks/test-with-deps/providers/provider.rb - spec/data/run_context/cookbooks/test-with-deps/recipes/default.rb - spec/data/run_context/cookbooks/test-with-deps/recipes/server.rb - spec/data/run_context/cookbooks/test-with-deps/resources/resource.rb - spec/data/run_context/nodes/run_context.rb - spec/data/search_queries_to_transform.txt - spec/data/shef-config.rb - spec/data/ssl/5e707473.0 - spec/data/ssl/chef-rspec.cert - spec/data/ssl/chef-rspec.key - spec/data/ssl/key.pem - spec/data/ssl/private_key.pem - spec/data/ssl/private_key_with_whitespace.pem - spec/data/templates/seattle.txt - spec/data/trusted_certs/example.crt - spec/data/trusted_certs/intermediate.pem - spec/data/trusted_certs/opscode.pem - spec/data/trusted_certs/root.pem - spec/functional/assets/dummy-1-0.aix6.1.noarch.rpm - spec/functional/assets/dummy-2-0.aix6.1.noarch.rpm - spec/functional/assets/mytest-1.0-1.noarch.rpm - spec/functional/assets/mytest-2.0-1.noarch.rpm - spec/functional/assets/PkgA.1.0.0.0.bff - spec/functional/assets/PkgA.2.0.0.0.bff - spec/functional/dsl/registry_helper_spec.rb - spec/functional/file_content_management/deploy_strategies_spec.rb - spec/functional/knife/cookbook_delete_spec.rb - spec/functional/knife/exec_spec.rb - spec/functional/knife/smoke_test.rb - spec/functional/knife/ssh_spec.rb - spec/functional/provider/remote_file/cache_control_data_spec.rb - spec/functional/resource/base.rb - spec/functional/resource/batch_spec.rb - spec/functional/resource/bff_spec.rb - spec/functional/resource/cookbook_file_spec.rb - spec/functional/resource/cron_spec.rb - spec/functional/resource/deploy_revision_spec.rb - spec/functional/resource/directory_spec.rb - spec/functional/resource/file_spec.rb - spec/functional/resource/git_spec.rb - spec/functional/resource/group_spec.rb - spec/functional/resource/ifconfig_spec.rb - spec/functional/resource/link_spec.rb - spec/functional/resource/mount_spec.rb - spec/functional/resource/package_spec.rb - spec/functional/resource/powershell_spec.rb - spec/functional/resource/registry_spec.rb - spec/functional/resource/remote_directory_spec.rb - spec/functional/resource/remote_file_spec.rb - spec/functional/resource/rpm_spec.rb - spec/functional/resource/template_spec.rb - spec/functional/resource/user_spec.rb - spec/functional/run_lock_spec.rb - spec/functional/shell_spec.rb - spec/functional/tiny_server_spec.rb - spec/functional/version_spec.rb - spec/functional/win32/registry_helper_spec.rb - spec/functional/win32/security_spec.rb - spec/functional/win32/service_manager_spec.rb - spec/functional/win32/versions_spec.rb - spec/integration/client/client_spec.rb - spec/integration/knife/chef_fs_data_store_spec.rb - spec/integration/knife/chef_repo_path_spec.rb - spec/integration/knife/chef_repository_file_system_spec.rb - spec/integration/knife/chefignore_spec.rb - spec/integration/knife/common_options_spec.rb - spec/integration/knife/delete_spec.rb - spec/integration/knife/deps_spec.rb - spec/integration/knife/diff_spec.rb - spec/integration/knife/download_spec.rb - spec/integration/knife/list_spec.rb - spec/integration/knife/raw_spec.rb - spec/integration/knife/redirection_spec.rb - spec/integration/knife/show_spec.rb - spec/integration/knife/upload_spec.rb - spec/integration/solo/solo_spec.rb - spec/rcov.opts - spec/spec_helper.rb - spec/stress/win32/file_spec.rb - spec/stress/win32/memory_spec.rb - spec/stress/win32/security_spec.rb - spec/support/chef_helpers.rb - spec/support/lib/chef/provider/easy.rb - spec/support/lib/chef/provider/snakeoil.rb - spec/support/lib/chef/resource/cat.rb - spec/support/lib/chef/resource/one_two_three_four.rb - spec/support/lib/chef/resource/with_state.rb - spec/support/lib/chef/resource/zen_master.rb - spec/support/lib/library_load_order.rb - spec/support/matchers/leak.rb - spec/support/mock/constant.rb - spec/support/mock/platform.rb - spec/support/platform_helpers.rb - spec/support/platforms/prof/gc.rb - spec/support/platforms/prof/win32.rb - spec/support/platforms/win32/spec_service.rb - spec/support/shared/functional/diff_disabled.rb - spec/support/shared/functional/directory_resource.rb - spec/support/shared/functional/file_resource.rb - spec/support/shared/functional/knife.rb - spec/support/shared/functional/securable_resource.rb - spec/support/shared/functional/securable_resource_with_reporting.rb - spec/support/shared/functional/windows_script.rb - spec/support/shared/integration/integration_helper.rb - spec/support/shared/integration/knife_support.rb - spec/support/shared/unit/api_error_inspector.rb - spec/support/shared/unit/execute_resource.rb - spec/support/shared/unit/file_system_support.rb - spec/support/shared/unit/platform_introspector.rb - spec/support/shared/unit/provider/file.rb - spec/support/shared/unit/provider/useradd_based_user_provider.rb - spec/support/shared/unit/script_resource.rb - spec/support/shared/unit/windows_script_resource.rb - spec/tiny_server.rb - spec/unit/api_client/registration_spec.rb - spec/unit/api_client_spec.rb - spec/unit/application/agent_spec.rb - spec/unit/application/apply.rb - spec/unit/application/client_spec.rb - spec/unit/application/knife_spec.rb - spec/unit/application/server_spec.rb - spec/unit/application/solo_spec.rb - spec/unit/application_spec.rb - spec/unit/checksum/storage/filesystem_spec.rb - spec/unit/chef_fs/diff_spec.rb - spec/unit/chef_fs/file_pattern_spec.rb - spec/unit/chef_fs/file_system/operation_failed_error_spec.rb - spec/unit/chef_fs/file_system_spec.rb - spec/unit/chef_spec.rb - spec/unit/client_spec.rb - spec/unit/config_fetcher_spec.rb - spec/unit/config_spec.rb - spec/unit/cookbook/chefignore_spec.rb - spec/unit/cookbook/metadata_spec.rb - spec/unit/cookbook/synchronizer_spec.rb - spec/unit/cookbook/syntax_check_spec.rb - spec/unit/cookbook_loader_spec.rb - spec/unit/cookbook_manifest_spec.rb - spec/unit/cookbook_site_streaming_uploader.rb - spec/unit/cookbook_spec.rb - spec/unit/cookbook_version_spec.rb - spec/unit/daemon_spec.rb - spec/unit/data_bag_item_spec.rb - spec/unit/data_bag_spec.rb - spec/unit/deprecation_spec.rb - spec/unit/digester_spec.rb - spec/unit/dsl/data_query_spec.rb - spec/unit/dsl/platform_introspection_spec.rb - spec/unit/dsl/regsitry_helper_spec.rb - spec/unit/encrypted_data_bag_item_spec.rb - spec/unit/environment_spec.rb - spec/unit/exceptions_spec.rb - spec/unit/file_access_control_spec.rb - spec/unit/file_cache_spec.rb - spec/unit/file_content_management/deploy/cp_spec.rb - spec/unit/file_content_management/deploy/mv_unix_spec.rb - spec/unit/file_content_management/deploy/mv_windows_spec.rb - spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb - spec/unit/formatters/error_inspectors/cookbook_resolve_error_inspector_spec.rb - spec/unit/formatters/error_inspectors/cookbook_sync_error_inspector_spec.rb - spec/unit/formatters/error_inspectors/node_load_error_inspector_spec.rb - spec/unit/formatters/error_inspectors/registration_error_inspector_spec.rb - spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb - spec/unit/formatters/error_inspectors/run_list_expansion_error_inspector_spec.rb - spec/unit/handler/json_file_spec.rb - spec/unit/handler_spec.rb - spec/unit/http/ssl_policies_spec.rb - spec/unit/json_compat_spec.rb - spec/unit/knife/bootstrap_spec.rb - spec/unit/knife/client_bulk_delete_spec.rb - spec/unit/knife/client_create_spec.rb - spec/unit/knife/client_delete_spec.rb - spec/unit/knife/client_edit_spec.rb - spec/unit/knife/client_list_spec.rb - spec/unit/knife/client_reregister_spec.rb - spec/unit/knife/client_show_spec.rb - spec/unit/knife/config_file_selection_spec.rb - spec/unit/knife/configure_client_spec.rb - spec/unit/knife/configure_spec.rb - spec/unit/knife/cookbook_bulk_delete_spec.rb - spec/unit/knife/cookbook_create_spec.rb - spec/unit/knife/cookbook_delete_spec.rb - spec/unit/knife/cookbook_download_spec.rb - spec/unit/knife/cookbook_list_spec.rb - spec/unit/knife/cookbook_metadata_from_file_spec.rb - spec/unit/knife/cookbook_metadata_spec.rb - spec/unit/knife/cookbook_show_spec.rb - spec/unit/knife/cookbook_site_download_spec.rb - spec/unit/knife/cookbook_site_install_spec.rb - spec/unit/knife/cookbook_site_share_spec.rb - spec/unit/knife/cookbook_site_unshare_spec.rb - spec/unit/knife/cookbook_test_spec.rb - spec/unit/knife/cookbook_upload_spec.rb - spec/unit/knife/core/bootstrap_context_spec.rb - spec/unit/knife/core/cookbook_scm_repo_spec.rb - spec/unit/knife/core/object_loader_spec.rb - spec/unit/knife/core/subcommand_loader_spec.rb - spec/unit/knife/core/ui_spec.rb - spec/unit/knife/data_bag_create_spec.rb - spec/unit/knife/data_bag_edit_spec.rb - spec/unit/knife/data_bag_from_file_spec.rb - spec/unit/knife/data_bag_show_spec.rb - spec/unit/knife/environment_create_spec.rb - spec/unit/knife/environment_delete_spec.rb - spec/unit/knife/environment_edit_spec.rb - spec/unit/knife/environment_from_file_spec.rb - spec/unit/knife/environment_list_spec.rb - spec/unit/knife/environment_show_spec.rb - spec/unit/knife/index_rebuild_spec.rb - spec/unit/knife/knife_help.rb - spec/unit/knife/node_bulk_delete_spec.rb - spec/unit/knife/node_delete_spec.rb - spec/unit/knife/node_edit_spec.rb - spec/unit/knife/node_from_file_spec.rb - spec/unit/knife/node_list_spec.rb - spec/unit/knife/node_run_list_add_spec.rb - spec/unit/knife/node_run_list_remove_spec.rb - spec/unit/knife/node_run_list_set_spec.rb - spec/unit/knife/node_show_spec.rb - spec/unit/knife/role_bulk_delete_spec.rb - spec/unit/knife/role_create_spec.rb - spec/unit/knife/role_delete_spec.rb - spec/unit/knife/role_edit_spec.rb - spec/unit/knife/role_from_file_spec.rb - spec/unit/knife/role_list_spec.rb - spec/unit/knife/ssh_spec.rb - spec/unit/knife/status_spec.rb - spec/unit/knife/tag_create_spec.rb - spec/unit/knife/tag_delete_spec.rb - spec/unit/knife/tag_list_spec.rb - spec/unit/knife/user_create_spec.rb - spec/unit/knife/user_delete_spec.rb - spec/unit/knife/user_edit_spec.rb - spec/unit/knife/user_list_spec.rb - spec/unit/knife/user_reregister_spec.rb - spec/unit/knife/user_show_spec.rb - spec/unit/knife_spec.rb - spec/unit/log_spec.rb - spec/unit/lwrp_spec.rb - spec/unit/mash_spec.rb - spec/unit/mixin/checksum_spec.rb - spec/unit/mixin/command_spec.rb - spec/unit/mixin/convert_to_class_name_spec.rb - spec/unit/mixin/deep_merge_spec.rb - spec/unit/mixin/deprecation_spec.rb - spec/unit/mixin/enforce_ownership_and_permissions_spec.rb - spec/unit/mixin/params_validate_spec.rb - spec/unit/mixin/path_sanity_spec.rb - spec/unit/mixin/securable_spec.rb - spec/unit/mixin/shell_out_spec.rb - spec/unit/mixin/template_spec.rb - spec/unit/mixin/windows_architecture_helper_spec.rb - spec/unit/mixin/xml_escape_spec.rb - spec/unit/monkey_patches/string_spec.rb - spec/unit/node/attribute_spec.rb - spec/unit/node/immutable_collections_spec.rb - spec/unit/node_spec.rb - spec/unit/platform_spec.rb - spec/unit/provider/breakpoint_spec.rb - spec/unit/provider/cookbook_file/content_spec.rb - spec/unit/provider/cookbook_file_spec.rb - spec/unit/provider/cron/unix_spec.rb - spec/unit/provider/cron_spec.rb - spec/unit/provider/deploy/revision_spec.rb - spec/unit/provider/deploy/timestamped_spec.rb - spec/unit/provider/deploy_spec.rb - spec/unit/provider/directory_spec.rb - spec/unit/provider/env_spec.rb - spec/unit/provider/erl_call_spec.rb - spec/unit/provider/execute_spec.rb - spec/unit/provider/file/content_spec.rb - spec/unit/provider/file_spec.rb - spec/unit/provider/git_spec.rb - spec/unit/provider/group/dscl_spec.rb - spec/unit/provider/group/gpasswd_spec.rb - spec/unit/provider/group/groupadd_spec.rb - spec/unit/provider/group/groupmod_spec.rb - spec/unit/provider/group/pw_spec.rb - spec/unit/provider/group/usermod_spec.rb - spec/unit/provider/group/windows_spec.rb - spec/unit/provider/group_spec.rb - spec/unit/provider/http_request_spec.rb - spec/unit/provider/ifconfig/aix_spec.rb - spec/unit/provider/ifconfig/debian_spec.rb - spec/unit/provider/ifconfig/redhat_spec.rb - spec/unit/provider/ifconfig_spec.rb - spec/unit/provider/link_spec.rb - spec/unit/provider/log_spec.rb - spec/unit/provider/mdadm_spec.rb - spec/unit/provider/mount/aix_spec.rb - spec/unit/provider/mount/mount_spec.rb - spec/unit/provider/mount/windows_spec.rb - spec/unit/provider/mount_spec.rb - spec/unit/provider/ohai_spec.rb - spec/unit/provider/package/aix_spec.rb - spec/unit/provider/package/apt_spec.rb - spec/unit/provider/package/dpkg_spec.rb - spec/unit/provider/package/easy_install_spec.rb - spec/unit/provider/package/freebsd_spec.rb - spec/unit/provider/package/ips_spec.rb - spec/unit/provider/package/macports_spec.rb - spec/unit/provider/package/pacman_spec.rb - spec/unit/provider/package/portage_spec.rb - spec/unit/provider/package/rpm_spec.rb - spec/unit/provider/package/rubygems_spec.rb - spec/unit/provider/package/smartos_spec.rb - spec/unit/provider/package/solaris_spec.rb - spec/unit/provider/package/yum_spec.rb - spec/unit/provider/package/zypper_spec.rb - spec/unit/provider/package_spec.rb - spec/unit/provider/powershell_spec.rb - spec/unit/provider/registry_key_spec.rb - spec/unit/provider/remote_directory_spec.rb - spec/unit/provider/remote_file/cache_control_data_spec.rb - spec/unit/provider/remote_file/content_spec.rb - spec/unit/provider/remote_file/fetcher_spec.rb - spec/unit/provider/remote_file/ftp_spec.rb - spec/unit/provider/remote_file/http_spec.rb - spec/unit/provider/remote_file/local_file_spec.rb - spec/unit/provider/remote_file_spec.rb - spec/unit/provider/route_spec.rb - spec/unit/provider/ruby_block_spec.rb - spec/unit/provider/script_spec.rb - spec/unit/provider/service/arch_service_spec.rb - spec/unit/provider/service/debian_service_spec.rb - spec/unit/provider/service/freebsd_service_spec.rb - spec/unit/provider/service/gentoo_service_spec.rb - spec/unit/provider/service/init_service_spec.rb - spec/unit/provider/service/insserv_service_spec.rb - spec/unit/provider/service/invokercd_service_spec.rb - spec/unit/provider/service/macosx_spec.rb - spec/unit/provider/service/redhat_spec.rb - spec/unit/provider/service/simple_service_spec.rb - spec/unit/provider/service/solaris_smf_service_spec.rb - spec/unit/provider/service/systemd_service_spec.rb - spec/unit/provider/service/upstart_service_spec.rb - spec/unit/provider/service/windows_spec.rb - spec/unit/provider/service_spec.rb - spec/unit/provider/subversion_spec.rb - spec/unit/provider/template/content_spec.rb - spec/unit/provider/template_spec.rb - spec/unit/provider/user/dscl_spec.rb - spec/unit/provider/user/pw_spec.rb - spec/unit/provider/user/solaris_spec.rb - spec/unit/provider/user/useradd_spec.rb - spec/unit/provider/user/windows_spec.rb - spec/unit/provider/user_spec.rb - spec/unit/provider_spec.rb - spec/unit/recipe_spec.rb - spec/unit/registry_helper_spec.rb - spec/unit/resource/apt_package_spec.rb - spec/unit/resource/bash_spec.rb - spec/unit/resource/batch_spec.rb - spec/unit/resource/breakpoint_spec.rb - spec/unit/resource/chef_gem_spec.rb - spec/unit/resource/conditional_action_not_nothing_spec.rb - spec/unit/resource/conditional_spec.rb - spec/unit/resource/cookbook_file_spec.rb - spec/unit/resource/cron_spec.rb - spec/unit/resource/csh_spec.rb - spec/unit/resource/deploy_revision_spec.rb - spec/unit/resource/deploy_spec.rb - spec/unit/resource/directory_spec.rb - spec/unit/resource/dpkg_package_spec.rb - spec/unit/resource/easy_install_package_spec.rb - spec/unit/resource/env_spec.rb - spec/unit/resource/erl_call_spec.rb - spec/unit/resource/execute_spec.rb - spec/unit/resource/file_spec.rb - spec/unit/resource/freebsd_package_spec.rb - spec/unit/resource/gem_package_spec.rb - spec/unit/resource/git_spec.rb - spec/unit/resource/group_spec.rb - spec/unit/resource/http_request_spec.rb - spec/unit/resource/ifconfig_spec.rb - spec/unit/resource/ips_package_spec.rb - spec/unit/resource/link_spec.rb - spec/unit/resource/log_spec.rb - spec/unit/resource/macports_package_spec.rb - spec/unit/resource/mdadm_spec.rb - spec/unit/resource/mount_spec.rb - spec/unit/resource/ohai_spec.rb - spec/unit/resource/package_spec.rb - spec/unit/resource/pacman_package_spec.rb - spec/unit/resource/perl_spec.rb - spec/unit/resource/portage_package_spec.rb - spec/unit/resource/powershell_spec.rb - spec/unit/resource/python_spec.rb - spec/unit/resource/registry_key_spec.rb - spec/unit/resource/remote_directory_spec.rb - spec/unit/resource/remote_file_spec.rb - spec/unit/resource/route_spec.rb - spec/unit/resource/rpm_package_spec.rb - spec/unit/resource/ruby_block_spec.rb - spec/unit/resource/ruby_spec.rb - spec/unit/resource/scm_spec.rb - spec/unit/resource/script_spec.rb - spec/unit/resource/service_spec.rb - spec/unit/resource/smartos_package_spec.rb - spec/unit/resource/solaris_package_spec.rb - spec/unit/resource/subversion_spec.rb - spec/unit/resource/template_spec.rb - spec/unit/resource/timestamped_deploy_spec.rb - spec/unit/resource/user_spec.rb - spec/unit/resource/yum_package_spec.rb - spec/unit/resource_collection/stepable_iterator_spec.rb - spec/unit/resource_collection_spec.rb - spec/unit/resource_definition_spec.rb - spec/unit/resource_platform_map_spec.rb - spec/unit/resource_reporter_spec.rb - spec/unit/resource_spec.rb - spec/unit/rest/auth_credentials_spec.rb - spec/unit/rest_spec.rb - spec/unit/role_spec.rb - spec/unit/run_context/cookbook_compiler_spec.rb - spec/unit/run_context_spec.rb - spec/unit/run_list/run_list_expansion_spec.rb - spec/unit/run_list/run_list_item_spec.rb - spec/unit/run_list/versioned_recipe_list_spec.rb - spec/unit/run_list_spec.rb - spec/unit/run_lock_spec.rb - spec/unit/run_status_spec.rb - spec/unit/runner_spec.rb - spec/unit/scan_access_control_spec.rb - spec/unit/search/query_spec.rb - spec/unit/shell/model_wrapper_spec.rb - spec/unit/shell/shell_ext_spec.rb - spec/unit/shell/shell_session_spec.rb - spec/unit/shell_out_spec.rb - spec/unit/shell_spec.rb - spec/unit/user_spec.rb - spec/unit/util/backup_spec.rb - spec/unit/util/diff_spec.rb - spec/unit/util/file_edit_spec.rb - spec/unit/util/selinux_spec.rb - spec/unit/version/platform_spec.rb - spec/unit/version_class_spec.rb - spec/unit/version_constraint/platform_spec.rb - spec/unit/version_constraint_spec.rb - spec/unit/windows_service_spec.rb - bin/chef-client - bin/chef-solo - bin/knife - bin/chef-shell - bin/shef - bin/chef-apply - bin/chef-service-manager homepage: http://wiki.opscode.com/display/chef licenses: [] post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 1.8.23 signing_key: specification_version: 3 summary: A systems integration framework, built to bring the benefits of configuration management to your entire infrastructure. test_files: [] chef-11.8.2/tasks/0000755000004100000410000000000012254362222013665 5ustar www-datawww-datachef-11.8.2/tasks/rspec.rb0000644000004100000410000000500212254362222015323 0ustar www-datawww-data# # Author:: Adam Jacob () # Author:: Daniel DeLeo () # Copyright:: Copyright (c) 2008, 2010 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # require 'rubygems' require 'rake' CHEF_ROOT = File.join(File.dirname(__FILE__), "..") begin require 'rspec/core/rake_task' task :default => :spec desc "Run all specs in spec directory" RSpec::Core::RakeTask.new(:spec) do |t| t.rspec_opts = ['--options', "\"#{CHEF_ROOT}/.rspec\""] t.pattern = FileList['spec/**/*_spec.rb'] end desc "Run all functional specs (in functional/ directory)" RSpec::Core::RakeTask.new(:functional) do |t| t.rspec_opts = ['--options', "\"#{CHEF_ROOT}/spec/spec.opts\""] t.pattern = FileList['spec/functional/**/*_spec.rb'] end desc "Run the rspec tests with activesupport loaded" RSpec::Core::RakeTask.new(:spec_activesupport) do |t| t.rspec_opts = ['--options', "\"#{CHEF_ROOT}/.rspec\"", "--require active_support/core_ext"] t.pattern = FileList['spec/unit/**/*_spec.rb'] end namespace :spec do desc "Run all specs in spec directory with RCov" RSpec::Core::RakeTask.new(:rcov) do |t| t.rspec_opts = ['--options', "\"#{CHEF_ROOT}/spec/spec.opts\""] t.pattern = FileList['spec/**/*_spec.rb'] t.rcov = true t.rcov_opts = lambda do IO.readlines("#{CHEF_ROOT}/spec/rcov.opts").map {|l| l.chomp.split " "}.flatten end end desc "Print Specdoc for all specs" RSpec::Core::RakeTask.new(:doc) do |t| t.rspec_opts = ["--format", "specdoc", "--dry-run"] t.pattern = FileList['spec/**/*_spec.rb'] end [:unit].each do |sub| desc "Run the specs under spec/#{sub}" RSpec::Core::RakeTask.new(sub) do |t| t.rspec_opts = ['--options', "\"#{CHEF_ROOT}/spec/spec.opts\""] t.pattern = FileList["spec/#{sub}/**/*_spec.rb"] end end end rescue LoadError STDERR.puts "\n*** RSpec not available. (sudo) gem install rspec to run unit tests. ***\n\n" end chef-11.8.2/CONTRIBUTING.md0000644000004100000410000002141112254362222014770 0ustar www-datawww-data# Contributing to Chef We are glad you want to contribute to Chef! The first step is the desire to improve the project. You can find the answers to additional frequently asked questions [on the wiki](http://wiki.opscode.com/display/chef/How+to+Contribute). ## Quick-contribute * Create an account on our [bug tracker](http://tickets.opscode.com) * Sign our contributor agreement (CLA) [ online](https://secure.echosign.com/public/hostedForm?formid=PJIF5694K6L) (keep reading if you're contributing on behalf of your employer) * Create a ticket for your change on the [bug tracker](http://tickets.opscode.com) * Link to your patch as a rebased git branch or pull request from the ticket * Resolve the ticket as fixed We regularly review contributions and will get back to you if we have any suggestions or concerns. ## The Apache License and the CLA/CCLA Licensing is very important to open source projects, it helps ensure the software continues to be available under the terms that the author desired. Chef uses the Apache 2.0 license to strike a balance between open contribution and allowing you to use the software however you would like to. The license tells you what rights you have that are provided by the copyright holder. It is important that the contributor fully understands what rights they are licensing and agrees to them. Sometimes the copyright holder isn't the contributor, most often when the contributor is doing work for a company. To make a good faith effort to ensure these criteria are met, Opscode requires a Contributor License Agreement (CLA) or a Corporate Contributor License Agreement (CCLA) for all contributions. This is without exception due to some matters not being related to copyright and to avoid having to continually check with our lawyers about small patches. It only takes a few minutes to complete a CLA, and you retain the copyright to your contribution. You can complete our contributor agreement (CLA) [ online](https://secure.echosign.com/public/hostedForm?formid=PJIF5694K6L). If you're contributing on behalf of your employer, have your employer fill out our [Corporate CLA](https://secure.echosign.com/public/hostedForm?formid=PIE6C7AX856) instead. ## Ticket Tracker (JIRA) The [ticket tracker](http://tickets.opscode.com) is the most important documentation for the code base. It provides significant historical information, such as: * Which release a bug fix is included in * Discussion regarding the design and merits of features * Error output to aid in finding similar bugs Each ticket should aim to fix one bug or add one feature. ## Using git You can get a quick copy of the chef repository by running `git clone git://github.com/opscode/chef.git`. For collaboration purposes, it is best if you create a Github account and fork the repository to your own account. Once you do this you will be able to push your changes to your Github repository for others to see and use. ### Branches and Commits You should submit your patch as a git branch named after the ticket, such as CHEF-1337. This is called a _topic branch_ and allows users to associate a branch of code with the ticket. It is a best practice to have your commit message have a _summary line_ that includes the ticket number, followed by an empty line and then a brief description of the commit. This also helps other contributors understand the purpose of changes to the code. CHEF-3435: Create deploy dirs before calling scm_provider The SCM providers have an assertation that requires the deploy directory to exist. The deploy provider will create missing directories, we don't converge the actions before we call run_action against the SCM provider, so it is not yet created. This ensures we run any converge actions waiting before we call the SCM provider. Remember that not all users use Chef in the same way or on the same operating systems as you, so it is helpful to be clear about your use case and change so they can understand it even when it doesn't apply to them. ### Github and Pull Requests All of Opscode's open source projects are available on [Github](http://www.github.com/opscode). We don't require you to use Github, and we will even take patch diffs attached to tickets on the tracker. However Github has a lot of convenient features, such as being able to see a diff of changes between a pull request and the main repository quickly without downloading the branch. If you do choose to use a pull request, please provide a link to the pull request from the ticket __and__ a link to the ticket from the pull request. Because pull requests only have two states, open and closed, we can't easily filter pull requests that are waiting for a reply from the author for various reasons. ### More information Additional help with git is available on the [Working with Git](http://wiki.opscode.com/display/chef/Working+with+Git) wiki page. ## Functional and Unit Tests There are rspec unit tests in the 'spec' directory. If you don't have rspec already installed, you can use the 'bundler' gem to help you get the necessary prerequisites by running `sudo gem install bundler` and then `bundle install` from the chef respository. You can run the chef client spec tests by running `rspec spec/*` or `rake spec` from the chef directory of the chef repository. These tests should pass successfully on Ruby 1.8 and 1.9 on all of the platforms that Chef runs on. It is good to run the tests once on your system before you get started to ensure they all pass so you have a valid baseline. After you write your patch, run the tests again to see if they all pass. If any don't pass, investigate them before submitting your patch. These tests don't modify your system, and sometimes tests fail because a command that would be run has changed because of your patch. This should be a simple fix. Other times the failure can show you that an important feature no longer works because of your change. Any new feature should have unit tests included with the patch with good code coverage to help protect it from future changes. Similarly, patches that fix a bug or regression should have a _regression test_. Simply put, this is a test that would fail without your patch but passes with it. The goal is to ensure this bug doesn't regress in the future. Consider a regular expression that doesn't match a certain pattern that it should, so you provide a patch and a test to ensure that the part of the code that uses this regular expression works as expected. Later another contributor may modify this regular expression in a way that breaks your use cases. The test you wrote will fail, signalling to them to research your ticket and use case and accounting for it. ## Code Review Opscode regularly reviews code contributions and provides suggestions for improvement in the code itself or the implementation. We find contributions by searching the ticket tracker for _resolved_ tickets with a status of _fixed_. If we have feedback we will reopen the ticket and you should resolve it again when you've made the changes or have a response to our feedback. When we believe the patch is ready to be merged, we update the status to _Fix Reviewed_. Depending on the project, these tickets are then merged within a week or two, depending on the current release cycle. At this point the ticket status will be updated to _Fix Committed_ or _Closed_. Please see the [Code Review](http://wiki.opscode.com/display/chef/Code+Review) page on the wiki for additional information. ## Release Cycle The versioning for the Chef project is X.Y.Z. * X is a major release, which may not be fully compatible with prior major releases * Y is a minor release, which adds both new features and bug fixes * Z is a patch release, which adds just bug fixes Major releases and have historically been once a year. Minor releases for Chef average every two months and patch releases come as needed. There are usually beta releases and release candidates (RC) of major and minor releases announced on the [chef-dev mailing list](http://lists.opscode.com/sympa/info/chef-dev). Once an RC is released, we wait at least three days to allow for testing for regressions before the final release. If a blocking regression is found then another RC is made containing the fix and the timer is reset. Once the official release is made, the release notes are available on the [Opscode blog](http://www.opscode.com/blog). ## Working with the community These resources will help you learn more about Chef and connect to other members of the Chef community: * [chef](http://lists.opscode.com/sympa/info/chef) and [chef-dev](http://lists.opscode.com/sympa/info/chef-dev) mailing lists * #chef and #chef-hacking IRC channels on irc.freenode.net * [Community Cookbook site](http://community.opscode.com) * [Chef wiki](http://wiki.opscode.com/display/chef) * Opscode Chef [product page](http://www.opscode.com/chef) chef-11.8.2/LICENSE0000644000004100000410000002514212254362222013551 0ustar www-datawww-data Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. chef-11.8.2/README.md0000644000004100000410000000626112254362222014024 0ustar www-datawww-data# Chef * Documentation: [http://docs.opscode.com](http://docs.opscode.com) * Source: [http://github.com/opscode/chef/tree/master](http://github.com/opscode/chef/tree/master) * Tickets/Issues: [http://tickets.opscode.com](http://tickets.opscode.com) * IRC: `#chef` and `#chef-hacking` on Freenode * Mailing list: [http://lists.opscode.com](http://lists.opscode.com) Chef is a configuration management tool designed to bring automation to your entire infrastructure. The [Chef Wiki](http://wiki.opscode.com/display/chef/Home) is the definitive source of user documentation. This README focuses on developers who want to modify Chef source code. For users who just want to run the latest and greatest Chef development version in their environment, see the [Installing Chef from HEAD](http://wiki.opscode.com/display/chef/Installing+Chef+from+HEAD) page on the wiki. ## Contributing/Development Before working on the code, if you plan to contribute your changes, you need to read the [Opscode Contributing document](http://wiki.opscode.com/display/chef/How+to+Contribute). You will also need to set up the repository with the appropriate branches. We document the process on the [Working with Git](http://wiki.opscode.com/display/chef/Working+with+git) page of the Chef wiki. Once your repository is set up, you can start working on the code. We do use TDD with RSpec, so you'll need to get a development environment running. ### Requirements Ruby 1.8.7+ (As of 2012-05-25 Ruby 1.8.6 should still work, except for CHEF-2329.) ### Environment In order to have a development environment where changes to the Chef code can be tested, we'll need to install a few things after setting up the Git repository. #### Non-Gem Dependencies Install these via your platform's preferred method; for example apt, yum, ports, emerge, etc. * [Git](http://git-scm.com/) * GCC and C Standard Libraries, header files, etc. (i.e., build-essential on debian/ubuntu) * Ruby development package #### Runtime Rubygem Dependencies First you'll need [bundler](http://github.com/carlhuda/bundler) which can be installed with a simple `gem install bundler`. Afterwords, do the following: bundle install ## Testing We use RSpec for unit/spec tests. It is not necessary to start the development environment to run the specs--they are completely standalone. rake spec # License Chef - A configuration management system | | | |:---------------------|:-----------------------------------------| | **Author:** | Adam Jacob () | **Copyright:** | Copyright (c) 2008-2012 Opscode, Inc. | **License:** | Apache License, Version 2.0 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. chef-11.8.2/distro/0000755000004100000410000000000012254362222014044 5ustar www-datawww-datachef-11.8.2/distro/windows/0000755000004100000410000000000012254362222015536 5ustar www-datawww-datachef-11.8.2/distro/windows/service_manager.rb0000644000004100000410000000160512254362222021217 0ustar www-datawww-data# # Author:: Seth Chisamore () # Copyright:: Copyright (c) 2011 Opscode, Inc. # License:: Apache License, Version 2.0 # # 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. # $stderr.puts "WARNING: service_manager.rb is changed to: chef-service-manager" $stderr.puts "Please use chef-service-manager instead of service_manager.rb to install and manage chef-client as a windows service." chef-11.8.2/distro/README0000644000004100000410000000012212254362222014717 0ustar www-datawww-dataInit scripts meant to be used with a gem installation via the bootstrap cookbook. chef-11.8.2/distro/common/0000755000004100000410000000000012254362222015334 5ustar www-datawww-datachef-11.8.2/distro/common/html/0000755000004100000410000000000012254362222016300 5ustar www-datawww-datachef-11.8.2/distro/common/html/chef-solo.8.html0000644000004100000410000002046512254362222021222 0ustar www-datawww-data chef-solo(8) - Runs chef in solo mode against a specified cookbook location.
  1. chef-solo(8)
  2. Chef Manual
  3. chef-solo(8)

NAME

chef-solo - Runs chef in solo mode against a specified cookbook location.

SYNOPSIS

chef-solo (options)

-c, --config CONFIG
The configuration file to use
-d, --daemonize
Daemonize the process
-g, --group GROUP
Group to set privilege to
-i, --interval SECONDS
Run chef-client periodically, in seconds
-j, --json-attributes JSON_ATTRIBS
Load attributes from a JSON file or URL
-l, --log_level LEVEL
Set the log level (debug, info, warn, error, fatal)
-L, --logfile LOGLOCATION
Set the log file location, defaults to STDOUT - recommended for daemonizing
-N, --node-name NODE_NAME
The node name for this client
-r, --recipe-url RECIPE_URL
Pull down a remote gzipped tarball of recipes and untar it to the cookbook cache.
-s, --splay SECONDS
The splay time for running at intervals, in seconds
-u, --user USER
User to set privilege to
-v, --version
Show chef version
-h, --help
Show this message

DESCRIPTION

Chef Solo allows you to run Chef Cookbooks in the absence of a Chef Server. To do this, the complete cookbook needs to be present on disk.

By default Chef Solo will look in /etc/chef/solo.rb for its configuration. This configuration file has two required variables: file_cache_path and cookbook_path.

For example: file_cache_path "/var/chef-solo" cookbook_path "/var/chef-solo/cookbooks"

For your own systems, you can change this to reflect any directory you like, but you'll need to specify absolute paths and the cookbook_path directory should be a subdirectory of the file_cache_path.

You can also specify cookbook_path as an array, passing multiple locations to search for cookbooks.

For example: file_cache_path "/var/chef-solo" cookbook_path ["/var/chef-solo/cookbooks", "/var/chef-solo/site-cookbooks"]

Note that earlier entries are now overridden by later ones.

Since chef-solo doesn't have any interaction with a Chef Server, you'll need to specify node-specifc attributes in a JSON file. This can be located on the target system itself, or it can be stored on a remote server such as S3, or a web server on your network.

Within the JSON file, you'll also specify the recipes that Chef should run in the "run_list". An example JSON file, which sets a resolv.conf:

{
  "resolver": {
    "nameservers": [ "10.0.0.1" ],
    "search":"int.example.com"
  },
  "run_list": [ "recipe[resolver]" ]
}

Then you can run chef-solo with -j to specify the JSON file. It will look for cookbooks in the cookbook_path configured in the configuration file, and apply attributes and use the run_list from the JSON file specified.

You can use -c to specify the path to the configuration file (if you don't want chef-solo to use the default). You can also specify -r for a cookbook tarball.

For example: chef-solo -c ~/solo.rb -j ~/node.json -r http://www.example.com/chef-solo.tar.gz

In the above case, chef-solo would extract the tarball to your specified cookbook_path, use ~/solo.rb as the configuration file, and apply attributes and use the run_list from ~/node.json.

SEE ALSO

Full documentation for Chef and chef-solo is located on the Chef wiki, http://wiki.opscode.com/display/chef/Home.

AUTHOR

Chef was written by Adam Jacob adam@ospcode.com of Opscode (http://www.opscode.com), with contributions from the community. This manual page was written by Joshua Timberman joshua@opscode.com with help2man. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

On Debian systems, the complete text of the Apache 2.0 License can be found in /usr/share/common-licenses/Apache-2.0.

  1. Chef 11.8.2
  2. December 2013
  3. chef-solo(8)
chef-11.8.2/distro/common/html/knife-configure.1.html0000644000004100000410000001651412254362222022407 0ustar www-datawww-data knife-configure(1) - Generate configuration files for knife or Chef Client
  1. knife-configure(1)
  2. Chef Manual
  3. knife-configure(1)

NAME

knife-configure - Generate configuration files for knife or Chef Client

SYNOPSIS

knife configure [client] (options)

DESCRIPTION

Generates a knife.rb configuration file interactively. When given the --initial option, also creates a new administrative user.

CONFIGURE SUBCOMMANDS

knife configure (options)

-i, --initial
Create an initial API Client
-r, --repository REPO
The path to your chef-repo

Create a configuration file for knife. This will prompt for values to enter into the file. Default values are listed in square brackets if no other entry is typed. See knife(1) for a description of configuration options.

knife configure client directory

Read the knife.rb config file and generate a config file suitable for use in /etc/chef/client.rb and copy the validation certificate into the specified directory.

EXAMPLES

  • On a freshly installed Chef Server, use knife configure -i to create an administrator and knife configuration file. Leave the field blank to accept the default value. On most systems, the default values are acceptable.

    user@host$ knife configure -i Please enter the chef server URL: [http://localhost:4000] Please enter a clientname for the new client: [username] Please enter the existing admin clientname: [chef-webui] Please enter the location of the existing admin client's private key: [/etc/chef/webui.pem] Please enter the validation clientname: [chef-validator] Please enter the location of the validation key: [/etc/chef/validation.pem] Please enter the path to a chef repository (or leave blank): Creating initial API user... Created (or updated) client[username] Configuration file written to /home/username/.chef/knife.rb

    This creates a new administrator client named username, writes a configuration file to /home/username/.chef/knife.rb, and the private key to /home/username/.chef/username.pem. The configuration file and private key may be copied to another system to facilitate administration of the Chef Server from a remote system. Depending on the value given for the Chef Server URL, you may need to modify that setting after copying to a remote host.

SEE ALSO

knife(1) knife-client(1)

AUTHOR

Chef was written by Adam Jacob adam@opscode.com with many contributions from the community.

DOCUMENTATION

This manual page was written by Joshua Timberman joshua@opscode.com. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

CHEF

Knife is distributed with Chef. http://wiki.opscode.com/display/chef/Home

  1. Chef 11.8.2
  2. December 2013
  3. knife-configure(1)
chef-11.8.2/distro/common/html/knife-tag.1.html0000644000004100000410000001275012254362222021177 0ustar www-datawww-data knife-tag(1) - Apply tags to nodes on a Chef Server
  1. knife-tag(1)
  2. Chef Manual
  3. knife-tag(1)

NAME

knife-tag - Apply tags to nodes on a Chef Server

SYNOPSIS

knife tag subcommand (options)

TAG SUBCOMMANDS

The following tag subcommands are available:

CREATE

knife tag create node tag [...]

Adds one or more tags to node

DELETE

knife tag delete node tag [...]

Removes one or more tags from node

LIST

knife tag list node

Lists the tags applied to node

SEE ALSO

knife-node(1)

AUTHOR

Chef was written by Adam Jacob adam@opscode.com with many contributions from the community.

DOCUMENTATION

This manual page was written by Daniel DeLeo dan@opscode.com. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

CHEF

Knife is distributed with Chef. http://wiki.opscode.com/display/chef/Home

  1. Chef 11.8.2
  2. December 2013
  3. knife-tag(1)
chef-11.8.2/distro/common/html/knife-index.1.html0000644000004100000410000001251412254362222021531 0ustar www-datawww-data knife-index(1) - Rebuild the search index on a Chef Server
  1. knife-index(1)
  2. Chef Manual
  3. knife-index(1)

NAME

knife-index - Rebuild the search index on a Chef Server

SYNOPSIS

knife index rebuild (options)

-y, --yes
don't bother to ask if I'm sure

DESCRIPTION

Rebuilds all the search indexes on the server. This is accomplished by deleting all objects from the search index, and then forwarding each item in the database to chef-expander(8) via rabbitmq-server(1). Depending on the number of objects in the database, it may take some time for all objects to be indexed and available for search.

SEE ALSO

knife-search(1)

AUTHOR

Chef was written by Adam Jacob adam@opscode.com with many contributions from the community.

DOCUMENTATION

This manual page was written by Joshua Timberman joshua@opscode.com. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

CHEF

Knife is distributed with Chef. http://wiki.opscode.com/display/chef/Home

  1. Chef 11.8.2
  2. December 2013
  3. knife-index(1)
chef-11.8.2/distro/common/html/knife-client.1.html0000644000004100000410000002075312254362222021704 0ustar www-datawww-data knife-client(1) - Manage Chef API Clients
  1. knife-client(1)
  2. Chef Manual
  3. knife-client(1)

NAME

knife-client - Manage Chef API Clients

SYNOPSIS

knife client sub-command (options)

SUB-COMMANDS

Client subcommands follow a basic create, read, update, delete (CRUD) pattern. The Following subcommands are available:

BULK DELETE

knife client bulk delete regex (options)

Delete clients where the client name matches the regular expression regex on the Chef Server. The regular expression should be given as a quoted string, and not surrounded by forward slashes.

CREATE

knife client create client name (options)

-a, --admin
Create the client as an admin
-f, --file FILE
Write the key to a file

Create a new client. This generates an RSA keypair. The private key will be displayed on STDOUT or written to the named file. The public half will be stored on the Server. For chef-client systems, the private key should be copied to the system as /etc/chef/client.pem.

Admin clients should be created for users that will use knife to access the API as an administrator. The private key will generally be copied to ~/.chef/client\_name.pem and referenced in the knife.rb configuration file.

DELETE

knife client delete client name (options)

Deletes a registered client.

EDIT

client edit client name (options)

Edit a registered client.

LIST

client list (options)

-w, --with-uri
Show corresponding URIs

List all registered clients.

REREGISTER

client reregister client name (options)

-f, --file FILE
Write the key to a file

Regenerate the RSA keypair for a client. The public half will be stored on the server and the private key displayed on STDOUT or written to the named file. This operation will invalidate the previous keypair used by the client, preventing it from authenticating with the Chef Server. Use care when reregistering the validator client.

SHOW

client show client name (options)

-a, --attribute ATTR
Show only one attribute

Show a client. Output format is determined by the --format option.

DESCRIPTION

Clients are identities used for communication with the Chef Server API, roughly equivalent to user accounts on the Chef Server, except that clients only communicate with the Chef Server API and are authenticated via request signatures.

In the typical case, there will be one client object on the server for each node, and the corresponding client and node will have identical names.

In the Chef authorization model, there is one special client, the "validator", which is authorized to create new non-administrative clients but has minimal privileges otherwise. This identity is used as a sort of "guest account" to create a client identity when initially setting up a host for management with Chef.

SEE ALSO

knife-node(1)

AUTHOR

Chef was written by Adam Jacob adam@opscode.com with many contributions from the community.

DOCUMENTATION

This manual page was written by Joshua Timberman joshua@opscode.com. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

CHEF

Knife is distributed with Chef. http://wiki.opscode.com/display/chef/Home

  1. Chef 11.8.2
  2. December 2013
  3. knife-client(1)
chef-11.8.2/distro/common/html/knife-exec.1.html0000644000004100000410000001352212254362222021346 0ustar www-datawww-data knife-exec(1) - Run user scripts using the Chef API DSL
  1. knife-exec(1)
  2. Chef Manual
  3. knife-exec(1)

NAME

knife-exec - Run user scripts using the Chef API DSL

SYNOPSIS

knife exec (options)

-E, --exec CODE
Provide a snippet of code to evaluate on the command line

DESCRIPTION

knife exec runs arbitrary ruby scripts in a context similar to that of the chef-shell(1) DSL. See the chef-shell documentation for a description of the commands available.

EXAMPLES

Make an API call against an arbitrary endpoint
knife exec -E 'api.get("nodes/fluke.localdomain/cookbooks")' => list of cookbooks for the node fluke.localdomain
Remove the role obsolete from all nodes
knife exec -E 'nodes.transform(:all){|n| n.run_list.delete("role[obsolete]")}'
Generate the expanded run list for hosts in the webserver role
knife exec -E 'nodes.find(:roles => "webserver") {|n| n.expand!; n[:recipes]}'

SEE ALSO

chef-shell(1)

AUTHOR

Chef was written by Adam Jacob adam@opscode.com with many contributions from the community.

DOCUMENTATION

This manual page was written by Joshua Timberman joshua@opscode.com. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

CHEF

Knife is distributed with Chef. http://wiki.opscode.com/display/chef/Home

  1. Chef 11.8.2
  2. December 2013
  3. knife-exec(1)
chef-11.8.2/distro/common/html/chef-solr.8.html0000644000004100000410000001674012254362222021226 0ustar www-datawww-data chef-solr(8) - Runs as Chef's search server
  1. chef-solr(8)
  2. Chef Manual
  3. chef-solr(8)

NAME

chef-solr - Runs as Chef's search server

SYNOPSIS

chef-solr (options)

-c, --config CONFIG
The configuration file to use
-d, --daemonize
Daemonize the process
-g, --group GROUP
Group to set privilege to
-l, --log_level LEVEL
Set the log level (debug, info, warn, error, fatal)
-L, --logfile LOGLOCATION
Set the log file location, defaults to STDOUT - recommended for daemonizing
-P, --pid PIDFILE
Set the PID file location, defaults to /tmp/chef-solr.pid
-D, --solr-data-dir PATH
Where the Solr data lives
-x, --solor-heap-size SIZE
Set the size of the Java Heap
-H, --solr-home-dir PATH
Solr home directory
-j, --java-opts OPTS
Raw options passed to Java
-x, --solor-heap-size
Set the size of the Java Heap
-W, --solr-jetty-dir PATH
Where to place the Solr Jetty instance
-u, --user USER
User to set privilege to
-v, --version
Show chef-solr version
-h, --help
Show this message

DESCRIPTION

Chef-solr provides search service for Chef. You need to have both chef-solr and chef-expander-cluster running in order for search to work.

Installation

Make sure you backed up your data if you are upgrading from a previous version. Run chef-solr-installer to upgrade your Chef Solr installation. Answer "yes" when prompted for confirmation. The process should look like this:

yourshell> chef-solr-installer
Configuration setting solr_heap_size is unknown and will be ignored

Chef Solr is already installed in /var/chef/solr
Do you want to overwrite the current install? All existing Solr data will be lost. [y/n] y
Removing the existing Chef Solr installation
  rm -rf /var/chef/solr
  rm -rf /var/chef/solr-jetty
  rm -rf /var/chef/solr/data
Creating Solr Home Directory
  mkdir -p /var/chef/solr
  entering /var/chef/solr
  tar zxvf /Users/ddeleo/opscode/chef/chef-solr/solr/solr-home.tar.gz
Creating Solr Data Directory
  mkdir -p /var/chef/solr/data
Unpacking Solr Jetty
  mkdir -p /var/chef/solr-jetty
  entering /var/chef/solr-jetty
  tar zxvf /Users/ddeleo/opscode/chef/chef-solr/solr/solr-jetty.tar.gz

Successfully installed Chef Solr.
You can restore your search index using `knife index rebuild`

SEE ALSO

chef-expander-cluster(8)

Full documentation for Chef and chef-server is located on the Chef wiki, http://wiki.opscode.com/display/chef/Home.

AUTHOR

Chef was written by Adam Jacob adam@ospcode.com of Opscode (http://www.opscode.com), with contributions from the community. This manual page was written by Joshua Timberman joshua@opscode.com with help2man. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

On Debian systems, the complete text of the Apache 2.0 License can be found in /usr/share/common-licenses/Apache-2.0.

  1. Chef 11.8.2
  2. December 2013
  3. chef-solr(8)
chef-11.8.2/distro/common/html/knife.1.html0000644000004100000410000003727712254362222020441 0ustar www-datawww-data knife(1) - Chef Server API client utility
  1. knife(1)
  2. Chef Manual
  3. knife(1)

NAME

knife - Chef Server API client utility

SYNOPSIS

knife sub-command [argument...] (options)

DESCRIPTION

Knife is a command-line utility used to manage data on a Chef server through the HTTP(S) API. Knife is organized into groups of subcommands centered around the various object types in Chef. Each category of subcommand is documented in its own manual page. Available topics are:

  • bootstrap
  • client
  • configure
  • cookbook-site
  • cookbook
  • data-bag
  • environment
  • exec
  • index
  • node
  • recipe
  • role
  • search
  • ssh
  • status
  • tag

If the knife manuals are in your MANPATH, you can access help for the above topics using man knife-TOPIC; otherwise, you can view the documentation using knife help TOPIC.

OPTIONS

-s, --server-url URL
Chef Server URL, corresponds to Chef::Config chef_server_url.
-k, --key KEY
API Client Key, corresponds to Chef::Config client_key.
-c, --config CONFIG
The configuration file to use
-E, --environment ENVIRONMENT
Set the Chef environment
-e, --editor EDITOR
Set the editor to use for interactive commands
-F, --format FORMAT
Which format to use for output. See FORMATS for details.
-d, --disable-editing
Do not open EDITOR, just accept the data as is
-u, --user USER
API Client Username, corresponds to Chef::Config node_name.
-p, --print-after
Show the data after a destructive operation
-v, --version
Show chef version
-V, --verbose
More verbose output. Use twice for max verbosity.
-y, --yes
Say yes to all prompts for confirmation
--defaults
Accept default values for all questions
--[no-]color
Use colored output. Color enabled by default.
-h, --help
Show the available options for a command.

SUB-COMMANDS

Sub-commands that operate on the basic Chef data types are structured as NOUN verb NOUN (options). For all data types, the following commands are available:

  • create (create)
  • list and show (read)
  • edit (update)
  • delete (destroy)

Knife also includes commands that take actions other than displaying or modifying data on the Chef Server, such as knife-ssh(1).

CONFIGURATION

The knife configuration file is a Ruby DSL to set configuration parameters for Knife's GENERAL OPTIONS. The default location for the config file is ~/.chef/knife.rb. If managing multiple Chef repositories, per-repository config files can be created. The file must be .chef/knife.rb in the current directory of the repository.

If the config file exists, knife uses these settings for GENERAL OPTIONS defaults.

  • node_name: User or client identity (i.e., name) to use for authenticating requests to the Chef Server.
  • client_key: Private key file to authenticate to the Chef server. Corresponds to the -k or --key option.
  • chef_server_url: URL of the Chef server. Corresponds to the -s or --server-url option. This is requested from the user when running this sub-command.
  • syntax_check_cache_path: Specifies the path to a directory where knife caches information about files that it has syntax checked.
  • validation_client_name: Specifies the name of the client used to validate new clients.
  • validation_key: Specifies the private key file to use when bootstrapping new hosts. See knife-client(1) for more information about the validation client.
  • cookbook_copyright, cookbook_email, cookbook_license, readme_format Used by knife cookbook create sub-command to specify the copyright holder, maintainer email, license and readme format (respectively) for new cookbooks. The copyright holder is listed as the maintainer in the cookbook's metadata and as the Copyright in the comments of the default recipe. The maintainer email is used in the cookbook metadata. The license determines what preamble to put in the comment of the default recipe, and is listed as the license in the cookbook metadata. Currently supported licenses are "apachev2" and "none". Any other values will result in an empty license in the metadata (needs to be filled in by the author), and no comment preamble in the default recipe. Currently supported readme formats are "md", "mkd", "txt", and "rdoc". Any other value will result in an unformatted README.

FILES

~/.chef/knife.rb

Ruby DSL configuration file for knife. See CONFIGURATION.

FORMATS

The amount of content displayed and the output format are modified by the --format option. If no alternate format is selected, the default is summary.

Valid formats are:

summary
displays the node in a custom, summarized format (default)
text
displays the node data in its entirety using the colorized tree display
json
displays the node in JSON format
yaml
displays the node in YAML format
pp
displays the node using Ruby's pretty printer.

For brevity, only the first character of the format is required, for example, -Fj will produce JSON format output.

CHEF WORKFLOW

When working with Chef and Knife in the local repository, the recommended workflow outline looks like:

  • Create repository. A skeleton sample is provided at http://github.com/opscode/chef-repo/.
  • Configure knife, see CONFIGURATION.
  • Download cookbooks from the Opscode cookbooks site, see COOKBOOK SITE SUB-COMMANDS.
  • Or, create new cookbooks, see cookbook create sub-command.
  • Commit changes to the version control system. See your tool's documentation.
  • Upload cookbooks to the Chef Server, see COOKBOOK SUB-COMMANDS.
  • Launch instances in the Cloud, OR provision new hosts; see CLOUD COMPUTING SUB-COMMANDS and BOOTSTRAP SUB-COMMANDS.
  • Watch Chef configure systems!

A note about git: Opscode and many folks in the Chef community use git, but it is not required, except in the case of the cookbook site vendor sub-command, as it uses git directly. Version control is strongly recommended though, and git fits with a lot of the workflow paradigms.

EXAMPLES

ENVIRONMENT

EDITOR
The text editor to use for editing data. The --editor option takes precedence over this value, and the --disable-editing option supresses data editing entirely.

SEE ALSO

chef-client(8) chef-server(8) chef-shell(1)

knife-bootstrap(1) knife-client(1) knife-configure(1) knife-cookbook-site(1) knife-cookbook(1) knife-data-bag(1) knife-environment(1) knife-exec(1) knife-index(1) knife-node(1) knife-recipe(1) knife-role(1) knife-search(1) knife-ssh(1) knife-tag(1)

Complete Chef documentation is available online: http://wiki.opscode.com/display/chef/Home/

JSON is JavaScript Object Notation http://json.org/

SOLR is an open source search engine. http://lucene.apache.org/solr/

git(1) is a version control system http://git-scm.com/

This manual page was generated from Markdown with ronn(1) http://rtomayko.github.com/ronn/ronn.1.html

AUTHOR

Chef was written by Adam Jacob adam@opscode.com of Opscode (http://www.opscode.com), with contributions from the community.

DOCUMENTATION

This manual page was written by Joshua Timberman joshua@opscode.com.

LICENSE

Both Chef and this documentation are released under the terms of the Apache 2.0 License. You may view the license online: http://www.apache.org/licenses/LICENSE-2.0.html On some systems, the complete text of the Apache 2.0 License may be found in /usr/share/common-licenses/Apache-2.0.

CHEF

Knife is distributed with Chef. http://wiki.opscode.com/display/chef/Home

  1. Chef 11.8.2
  2. December 2013
  3. knife(1)
chef-11.8.2/distro/common/html/chef-shell.1.html0000644000004100000410000003117612254362222021347 0ustar www-datawww-data chef-shell(1) - Interactive Chef Console
  1. chef-shell(1)
  2. Chef Manual
  3. chef-shell(1)

NAME

chef-shell - Interactive Chef Console

SYNOPSIS

chef-shell [named configuration] (options)

-S, --server CHEF_SERVER_URL
The chef server URL
-z, --client
chef-client mode
-c, --config CONFIG
The configuration file to use
-j, --json-attributes JSON_ATTRIBS
Load attributes from a JSON file or URL
-l, --log-level LOG_LEVEL
Set the logging level
-s, --solo
chef-solo session
-a, --standalone
standalone session
-v, --version
Show chef version
-h, --help
Show command options

When no --config option is specified, chef-shell attempts to load a default configuration file:

  • If a named configuration is given, chef-shell will load ~/.chef/named configuration/chef_shell.rb
  • If no named configuration is given chef-shell will load ~/.chef/chef_shell.rb if it exists
  • chef-shell falls back to loading /etc/chef/client.rb or /etc/chef/solo.rb if -z or -s options are given and no chef_shell.rb can be found.
  • The --config option takes precedence over implicit configuration paths.

DESCRIPTION

chef-shell is an irb(1) (interactive ruby) session customized for Chef. chef-shell serves two primary functions: it provides a means to interact with a Chef Server interactively using a convenient DSL; it allows you to define and run Chef recipes interactively.

SYNTAX

chef-shell uses irb's subsession feature to provide multiple modes of interaction. In addition to the primary mode which is entered on start, recipe and attributes modes are available.

PRIMARY MODE

The following commands are available in the primary session:

help
Prints a list of available commands
version
Prints the Chef version
recipe
Switches to recipe mode
attributes
Switches to attributes mode
run_chef
Initiates a chef run
reset
reinitializes chef-shell session
echo :on|:off
Turns irb's echo function on or off. Echo is on by default.
tracing :on|:off
Turns irb's function tracing feature on or off. Tracing is extremely verbose and expected to be of interest primarily to developers.
node
Returns the node object for the current host. See knife-node(1) for more information about nodes.
ohai
Prints the attributes of node

In addition to these commands, chef-shell provides a DSL for accessing data on the Chef Server. When working with remote data in chef-shell, you chain method calls in the form object type.operation, where object type is in plural form. The following object types are available:

  • nodes
  • roles
  • data_bags
  • clients
  • cookbooks

For each object type the following operations are available:

object type.all(&block)
Loads all items from the server. If the optional code block is given, each item will be passed to the block and the results returned, similar to ruby's Enumerable#map method.
object type.show(object name)

Aliased as object type.load

Loads the singular item identified by object name.

object type.search(query, &block)

Aliased as object type.find

Runs a search against the server and returns the matching items. If the optional code block is given each item will be passed to the block and the results returned.

The query may be a Solr/Lucene format query given as a String, or a Hash of conditions. If a Hash is given, the options will be ANDed together. To join conditions with OR, use negative queries, or any advanced search syntax, you must provide give the query in String form.

object type.transform(:all|query, &block)

Aliased as object type.bulk_edit

Bulk edit objects by processing them with the (required) code block. You can edit all objects of the given type by passing the Symbol :all as the argument, or only a subset by passing a query as the argument. The query is evaluated in the same way as with search.

The return value of the code block is used to alter the behavior of transform. If the value returned from the block is nil or false, the object will not be saved. Otherwise, the object is saved after being passed to the block. This behavior can be exploited to create a dry run to test a data transformation.

RECIPE MODE

Recipe mode implements Chef's recipe DSL. Exhaustively documenting this DSL is outside the scope of this document. See the following pages in the Chef documentation for more information:

Once you have defined resources in the recipe, you can trigger a convergence run via run_chef

EXAMPLES

  • A "Hello World" interactive recipe

    chef > recipe chef:recipe > echo :off chef:recipe > file "/tmp/hello_world" chef:recipe > run_chef [Sat, 09 Apr 2011 08:56:56 -0700] INFO: Processing file[/tmp/hello_world] action create ((irb#1) line 2) [Sat, 09 Apr 2011 08:56:56 -0700] INFO: file[/tmp/hello_world] created file /tmp/hello_world chef:recipe > pp ls '/tmp' [".", "..", "hello_world"]

  • Search for nodes by role, and print their IP addresses

    chef > nodes.find(:roles => 'monitoring-server') {|n| n[:ipaddress] } => ["10.254.199.5"]

  • Remove the role obsolete from every node in the system

    chef > nodes.transform(:all) {|n| n.run_list.delete('role[obsolete]') } => [node[chef098b2.opschef.com], node[ree-woot], node[graphite-dev], node[fluke.localdomain], node[ghost.local], node[kallistec]]

BUGS

chef-shell often does not perfectly replicate the context in which chef-client(8) configures a host, which may lead to discrepancies in observed behavior.

chef-shell has to duplicate much code from chef-client's internal libraries and may become out of sync with the behavior of those libraries.

SEE ALSO

chef-client(8) knife(1) http://wiki.opscode.com/display/chef/Chef+Shell

AUTHOR

Chef was written by Adam Jacob adam@opscode.com with many contributions from the community. chef-shell was written by Daniel DeLeo.

DOCUMENTATION

This manual page was written by Daniel DeLeo dan@opscode.com. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

CHEF

chef-shell is distributed with Chef. http://wiki.opscode.com/display/chef/Home

  1. Chef 11.8.2
  2. December 2013
  3. chef-shell(1)
chef-11.8.2/distro/common/html/knife-role.1.html0000644000004100000410000001741612254362222021371 0ustar www-datawww-data knife-role(1) - Group common configuration settings
  1. knife-role(1)
  2. Chef Manual
  3. knife-role(1)

NAME

knife-role - Group common configuration settings

SYNOPSIS

knife role sub-command (options)

ROLE SUB-COMMANDS

The following role subcommands are available:

LIST

knife role list (options)

-w, --with-uri
Show corresponding URIs

List roles.

SHOW

knife role show ROLE (options)

-a, --attribute ATTR
Show only one attribute

Show a specific role.

CREATE

knife role create ROLE (options)

-d, --description
The role description

Create a new role.

EDIT

knife role edit ROLE (options)

Edit a role.

FROM FILE

knife role from file FILE (options)

Create or update a role from a role Ruby DSL (.rb) or JSON file.

DELETE

knife role delete ROLE (options)

Delete a role.

BULK DELETE

knife role bulk delete REGEX (options)

Delete roles on the Chef Server based on a regular expression. The regular expression (REGEX) should be in quotes, not in //'s.

DESCRIPTION

Roles provide a mechanism to group repeated configuration settings. Roles are data structures that contain default_attributes, and override_attributes, which are nested hashes of configuration settings, and a run_list, which is an ordered list of recipes and roles that should be applied to a host by chef-client.

default_attributes will be overridden if they conflict with a value on a node that includes the role. Conversely, override_attributes will override any values set on nodes that apply them.

When chef-client(8) configures a host, it will "expand" the run_list included in that host's node data. The expansion process will recursively replace any roles in the run_list with that role's run_list.

SEE ALSO

knife-node(1) knife-environment(1) http://wiki.opscode.com/display/chef/Roles http://wiki.opscode.com/display/chef/Attributes

AUTHOR

Chef was written by Adam Jacob adam@opscode.com with many contributions from the community.

DOCUMENTATION

This manual page was written by Joshua Timberman joshua@opscode.com. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

CHEF

Knife is distributed with Chef. http://wiki.opscode.com/display/chef/Home

  1. Chef 11.8.2
  2. December 2013
  3. knife-role(1)
chef-11.8.2/distro/common/html/chef-expander.8.html0000644000004100000410000001631212254362222022050 0ustar www-datawww-data chef-expander(8) - fetches messages from RabbitMQ, processes, and loads into chef-solr
  1. chef-expander(8)
  2. Chef Manual
  3. chef-expander(8)

NAME

chef-expander - fetches messages from RabbitMQ, processes, and loads into chef-solr

SYNOPSIS

chef-expander (options)

-c, --config CONFIG_FILE
a configuration file to use
-i, --index INDEX
the slot this node will occupy in the ring
-n, --node-count NUMBER
the number of nodes in the ring
-l, --log-level LOG_LEVEL
set the log level
-L, --logfile LOG_LOCATION
Logfile to use
-d, --daemonize
fork into the background
-P, --pid PIDFILE
PID file
-h, --help
show help message
-v, --version
show the version and exit

DESCRIPTION

Chef Expander fetches messages from RabbitMQ, processes them into the correct format to be loaded into Solr and loads them into Solr.

Running Chef Expander

Chef Expander is designed for clustered operation, though small installations will only need one worker process. To run Chef Expander with one worker process, run chef-expander -n 1. You will then have a master and worker process, which looks like this in ps:

your-shell> ps aux|grep expander
you   52110   0.1  0.7  2515476  62748 s003  S+    3:49PM   0:00.80 chef-expander worker #1 (vnodes 0-1023)
you   52108   0.1  0.5  2492880  41696 s003  S+    3:49PM   0:00.91 ruby bin/chef-expander -n 1

Workers are single threaded and therefore cannot use more than 100% of a single CPU. If you find that your queues are getting backlogged, increase the number of workers

Design

Chef Expander uses 1024 queues (called vnodes in some places) to allow you to scale the number of Chef Expander workers to meet the needs of your infrastructure. When objects are saved in the API server, they are added to queues based on their database IDs. These queues can be assigned to different Chef Expander workers to distribute the load of processing the index updates.

Chef Expander Operation and Troubleshooting

Chef Expander includes chef-expanderctl, a management program that allows you to get status information or change the logging verbosity (without restarting).

See chef-expanderctl(8) for details.

SEE ALSO

chef-expanderctl(8) chef-solr(8)

Full documentation for Chef and chef-server is located on the Chef wiki, http://wiki.opscode.com/display/chef/Home.

AUTHOR

Chef was written by Adam Jacob adam@ospcode.com of Opscode (http://www.opscode.com), with contributions from the community. This manual page was created by Nuo Yan nuo@opscode.com. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

On Debian systems, the complete text of the Apache 2.0 License can be found in /usr/share/common-licenses/Apache-2.0.

  1. Chef 11.8.2
  2. December 2013
  3. chef-expander(8)
chef-11.8.2/distro/common/html/knife-cookbook.1.html0000644000004100000410000004165412254362222022237 0ustar www-datawww-data knife-cookbook(1) - upload and manage chef cookbooks
  1. knife-cookbook(1)
  2. Chef Manual
  3. knife-cookbook(1)

NAME

knife-cookbook - upload and manage chef cookbooks

SYNOPSIS

knife cookbook sub-command (options)

SUB-COMMANDS

knife cookbook supports the following sub commands:

LIST

knife cookbook list (options)

-a, --all
show all versions of a cookbook instead of just the most recent
-w, --with-uri
show corresponding uris

Lists the cookbooks available on the Chef server.

SHOW

knife cookbook show cookbook [version] [part] [filename] (options)

-f, --fqdn fqdn
the fqdn of the host to see the file for
-p, --platform platform
the platform to see the file for
-v, --platform-version version
the platform version to see the file for
-w, --with-uri
Show corresponding URIs

show a particular part of a cookbook for the specified version. part can be one of:

  • attributes
  • definitions
  • files
  • libraries
  • providers
  • recipes
  • resources
  • templates

UPLOAD

knife cookbook upload [cookbooks...] (options)

-a, --all
upload all cookbooks, rather than just a single cookbook
-o, --cookbook-path path:path
a colon-separated path to look for cookbooks in
-d, --upload-dependencies
Uploads additional cookbooks that this cookbook lists in as dependencies in its metadata.
-E, --environment ENVIRONMENT
An ENVIRONMENT to apply the uploaded cookbooks to. Specifying this option will cause knife to edit the ENVIRONMENT to place a strict version constraint on the cookbook version(s) uploaded.
--freeze
Sets the frozen flag on the uploaded cookbook(s) Any future attempt to modify the cookbook without changing the version number will return an error unless --force is specified.
--force
Overrides the frozen flag on a cookbook, allowing you to overwrite a cookbook version that has previously been uploaded with the --freeze option.

Uploads one or more cookbooks from your local cookbook repository(ies) to the Chef Server. Only files that don't yet exist on the server will be uploaded.

As the command parses the name args as 1..n cookbook names: knife cookbook upload COOKBOOK COOKBOOK ... works for one to many cookbooks.

DOWNLOAD

knife cookbook download cookbook [version] (options)

-d, --dir download_directory
the directory to download the cookbook into
-f, --force
overwrite an existing directory with the download
-n, --latest
download the latest version of the cookbook

download a cookbook from the chef server. if no version is specified and only one version exists on the server, that version will be downloaded. if no version is specified and multiple versions are available on the server, you will be prompted for a version to download.

DELETE

knife cookbook delete cookbook [version] (options)

-a, --all
delete all versions
-p, --purge
purge files from backing store. this will disable any cookbook that contains any of the same files as the cookbook being purged.

delete the specified version of the named cookbook. if no version is specified, and only one version exists on the server, that version will be deleted. if multiple versions are available on the server, you will be prompted for a version to delete.

BULK DELETE

knife cookbook bulk delete regex (options)

-p, --purge
purge files from backing store. this will disable any cookbook that contains any of the same files as the cookbook being purged.

delete cookbooks on the chef server based on a regular expression. the regular expression (regex) should be in quotes, not in //'s.

COOKBOOK CREATE

knife cookbook create cookbook (options)

-o, --cookbook-path path
the directory where the cookbook will be created
-r, --readme-format format
format of the readme file md, mkd, txt, rdoc
-C, --copyright copyright
name of copyright holder
-i, --license license
license for cookbook, apachev2 or none
-m, --email email
email address of cookbook maintainer

this is a helper command that creates a new cookbook directory in the cookbook_path. the following directories and files are created for the named cookbook.

  • cookbook/attributes
  • cookbook/definitions
  • cookbook/files/default
  • cookbook/libraries
  • cookbook/metadata.rb
  • cookbook/providers
  • cookbook/readme.md
  • cookbook/recipes/default.rb
  • cookbook/resources
  • cookbook/templates/default

supported readme formats are 'md' (default), 'mkd', 'txt', 'rdoc'. the readme file will be written with the specified extension and a set of helpful starting headers.

specify -C or --copyright with the name of the copyright holder as your name or your company/organization name in a quoted string. if this value is not specified an all-caps string your_company_name is used which can be easily changed with find/replace.

specify -i or --license with the license that the cookbook is distributed under for sharing with other people or posting to the opscode cookbooks site. be aware of the licenses of files you put inside the cookbook and follow any restrictions they describe. when using none (default) or apachev2, comment header text and metadata file are pre-filled. the none license will be treated as non-redistributable.

specify -m or --email with the email address of the cookbook's maintainer. if this value is not specified, an all-caps string your_email is used which can easily be changed with find/replace.

the cookbook copyright, license, email and readme_format settings can be filled in the knife.rb, for example with default values:

cookbook_copyright "your_company_name"
cookbook_license "none"
cookbook_email "your_email"
readme_format "md"

METADATA

knife cookbook metadata cookbook (options)

-a, --all
generate metadata for all cookbooks, rather than just a single cookbook
-o, --cookbook-path path:path
a colon-separated path to look for cookbooks in

generate cookbook metadata for the named cookbook. the path used here specifies where the cookbooks directory is located and corresponds to the cookbook_path configuration option.

METADATA FROM FILE

knife cookbook metadata from file (options)

load the cookbook metadata from a specified file.

TEST

knife cookbook test [cookbooks...] (options)

-a, --all
test all cookbooks, rather than just a single cookbook
-o, --cookbook-path path:path
a colon-separated path to look for cookbooks in

test the specified cookbooks for syntax errors. this uses the built-in ruby syntax checking option for files in the cookbook ending in .rb, and the erb syntax check for files ending in .erb (templates).

RECIPE LIST

knife recipe list [PATTERN]

List available recipes from the server. Specify PATTERN as a regular expression to limit the results.

DESCRIPTION

Cookbooks are the fundamental unit of distribution in Chef. They encapsulate all recipes of resources and assets used to configure a particular aspect of the infrastructure. The following sub-commands can be used to manipulate the cookbooks stored on the Chef Server.

On disk, cookbooks are directories with a defined structure. The following directories may appear within a cookbook:

COOKBOOK/attributes/
Ruby files that define default parameters to be used in recipes
COOKBOOK/definitions/
Ruby files that contain resource definitions
COOKBOOK/files/SPECIFICITY
Files of arbitrary type. These files may be downloaded by chef-client(8) when configuring a host.
COOKBOOK/libraries/
Ruby files that contain library code needed for recipes
COOKBOOK/providers/
Ruby files that contain Lightweight Provider definitions
COOKBOOK/recipes/
Ruby files that use Chef's recipe DSL to describe the desired configuration of a system
COOKBOOK/resources/
Ruby files that contain Lightweight Resource definitions
COOKBOOK/templates/SPECIFICITY
ERuby (ERb) template files. These are referenced by recipes and evaluated to dynamically generate configuration files.

SPECIFICITY is a feature of files and templates that allow you to specify alternate files to be used on a specific OS platform or host. The default specificity setting is default, that is files in COOKBOOK/files/default will be used when a more specific copy is not available. Further documentation for this feature is available on the Chef wiki: http://wiki.opscode.com/display/chef/File+Distribution#FileDistribution-FileSpecificity

Cookbooks also contain a metadata file that defines various properties of the cookbook. The most important of these are the version and the dependencies. The version is used in combination with environments to select which copy of a given cookbook is distributed to a node. The dependencies are used by the server to determine which additional cookbooks must be distributed to a given host when it requires a cookbook.

SEE ALSO

knife-environment(1) knife-cookbook-site(1) http://wiki.opscode.com/display/chef/Cookbooks http://wiki.opscode.com/display/chef/Metadata

AUTHOR

Chef was written by Adam Jacob adam@opscode.com with many contributions from the community.

DOCUMENTATION

This manual page was written by Joshua Timberman joshua@opscode.com. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

CHEF

Knife is distributed with Chef. http://wiki.opscode.com/display/chef/Home

  1. Chef 11.8.2
  2. December 2013
  3. knife-cookbook(1)
chef-11.8.2/distro/common/html/knife-status.1.html0000644000004100000410000001306012254362222021742 0ustar www-datawww-data knife-status(1) - Display status information for the nodes in your infrastructure
  1. knife-status(1)
  2. Chef Manual
  3. knife-status(1)

NAME

knife-status - Display status information for the nodes in your infrastructure

SYNOPSIS

knife status (options)

-r, --run-list RUN_LIST
Show the run list

DESCRIPTION

The status sub-command searches the Chef Server for all nodes and displays information about the last time the node checked into the server and executed a node.save. The fields displayed are the relative checkin time, the node name, it's operating system platform and version, the fully-qualified domain name and the default IP address. If the -r option is given, the node's run list will also be displayed. Note that depending on the configuration of the nodes, the FQDN and IP displayed may not be publicly reachable.

SEE ALSO

knife-search(1)

AUTHOR

Chef was written by Adam Jacob adam@opscode.com with many contributions from the community.

DOCUMENTATION

This manual page was written by Joshua Timberman joshua@opscode.com. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

CHEF

Knife is distributed with Chef. http://wiki.opscode.com/display/chef/Home

  1. Chef 11.8.2
  2. December 2013
  3. knife-status(1)
chef-11.8.2/distro/common/html/knife-ssh.1.html0000644000004100000410000001645012254362222021222 0ustar www-datawww-data knife-ssh(1) - Run a command or interactive session on multiple remote hosts
  1. knife-ssh(1)
  2. Chef Manual
  3. knife-ssh(1)

NAME

knife-ssh - Run a command or interactive session on multiple remote hosts

SYNOPSIS

knife ssh QUERY COMMAND (options)

-a, --attribute ATTR
The attribute to use for opening the connection - default is fqdn
-C, --concurrency NUM
The number of concurrent connections
-m, --manual-list
QUERY is a space separated list of servers
-P, --ssh-password PASSWORD
The ssh password
-x, --ssh-user USERNAME
The ssh username
-i, --identity-file IDENTITY_FILE
The SSH identity file used for authentication
-p, --ssh-port PORT
The ssh port
--[no-]host-key-verify
Verify host key, enabled by default.

DESCRIPTION

The ssh sub-command opens an ssh session to each of the nodes in the search results of the QUERY. This sub-command requires that the net-ssh-multi and highline Ruby libraries are installed. On Debian systems, these are the libnet-ssh-multi-ruby and libhighline-ruby packages. They can also be installed as RubyGems (net-ssh-multi and highline, respectively).

TERMINAL MULTIPLEXING AND TERMINAL TAB SUPPORT

knife ssh integrates with several terminal multiplexer programs to provide a more convenient means of managing multiple ssh sessions. When the COMMAND option matches one of these, knife ssh will create multiple interactive ssh sessions running locally in the terminal multiplexer instead of invoking the command on the remote host.

The available multiplexers are:

interactive
A built-in multiplexer. interactive supports running commands on a subset of the connected hosts in parallel
screen(1)
Runs ssh interactively inside screen. ~/.screenrc will be sourced if it exists.
tmux(1)
Runs ssh interactively inside tmux.
macterm (Mac OS X only)
Opens a Terminal.app window and creates a tab for each ssh session. You must install the rb-appscript gem before you can use this option.

SEE ALSO

knife-search(1)

AUTHOR

Chef was written by Adam Jacob adam@opscode.com with many contributions from the community.

DOCUMENTATION

This manual page was written by Joshua Timberman joshua@opscode.com. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

CHEF

Knife is distributed with Chef. http://wiki.opscode.com/display/chef/Home

  1. Chef 11.8.2
  2. December 2013
  3. knife-ssh(1)
chef-11.8.2/distro/common/html/knife-search.1.html0000644000004100000410000002602012254362222021664 0ustar www-datawww-data knife-search(1) - Find objects on a Chef Server by query
  1. knife-search(1)
  2. Chef Manual
  3. knife-search(1)

NAME

knife-search - Find objects on a Chef Server by query

SYNOPSIS

knife search INDEX QUERY (options)

-a, --attribute ATTR
Show only one attribute
-i, --id-only
Show only the ID of matching objects
-q, --query QUERY
The search query; useful to protect queries starting with -
-R, --rows INT
The number of rows to return
-r, --run-list
Show only the run list
-o, --sort SORT
The order to sort the results in
-b, --start ROW
The row to start returning results at
-m, --medium
Display medium sized output when searching nodes using the default summary format
-l, --long
Display long output when searching nodes using the default summary format

DESCRIPTION

Search is a feature of the Chef Server that allows you to use a full-text search engine to query information about your infrastructure and applications. You can utilize this service via search calls in a recipe or the knife search command. The search syntax is based on Lucene.

INDEXES

Search indexes are a feature of the Chef Server and the search sub-command allows querying any of the available indexes using SOLR query syntax. The following data types are indexed for search:

  • node
  • role
  • environment
  • clients
  • data bag

Data bags are indexed by the data bag's name. For example, to search a data bag named "admins":

knife search admins "field:search_pattern"

QUERY SYNTAX

Queries have the form field:search_pattern where field is a key in the JSON description of the relevant objects (nodes, roles, environments, or data bags). Both field and search_pattern are case-sensitive. search_pattern can be an exact, wildcard, range, or fuzzy match (see below). The field supports exact matching and limited wildcard matching.

Searches will return the relevant objects (nodes, roles, environments, or data bags) where the search_pattern matches the object's value of field.

FIELD NAMES

Field names are the keys within the JSON description of the object being searched. Nested Keys can be searched by placing an underscore ("_") between key names.

WILDCARD MATCHING FOR FIELD NAMES

The field name also has limited support for wildcard matching. Both the "*" and "?" wildcards (see below) can be used within a field name; however, they cannot be the first character of the field name.

EXACT MATCHES

Without any search modifiers, a search returns those fields for which the search_pattern exactly matches the value of field in the JSON description of the object.

WILDCARD MATCHES

Search support both single- and multi-character wildcard searches within a search pattern.

'?' matches exactly one character.

'*' matches zero or more characters.

RANGE MATCHES

Range searches allows one to match values between two given values. To match values between X and Y, inclusively, use square brackets:

knife search INDEX 'field:[X TO Y]

To match values between X and Y, exclusively, use curly brackets:

knife search INDEX 'field:{X TO Y}'

Values are sorted in lexicographic order.

FUZZY MATCHES

Fuzzy searches allows one to match values based on the Levenshtein Distance algorithm. To perform a fuzzy match, append a tilda (~) to the search term:

knife search INDEX 'field:term~'

This search would return nodes whose field was 'perm' or 'germ'.

BOOLEAN OPERATORS

The boolean operators NOT, AND, and OR are supported. To find values of field that are not X:

knife search INDEX 'field:(NOT X)'

To find records where field1 is X and field2 is Y:

knife search INDEX 'field1:X AND field2:Y'

To find records where field is X or Y:

knife search INDEX 'field:X OR field:Y'

QUOTING AND SPECIAL CHARACTERS

In order to avoid having special characters and escape sequences within your search term interpreted by either Ruby or the shell, enclose them in single quotes.

Search terms that include spaces should be enclosed in double-quotes:

knife search INDEX 'field:"term with spaces"'

The following characters must be escaped:

+ - && || ! ( ) { } [ ] ^ " ~ * ? : \

EXAMPLES

Find the nodes with the fully-qualified domain name (FQDN) www.example.com:

knife search node 'fqdn:www.example.com'

Find the nodes running a version of Ubuntu:

knife search node 'platform:ubuntu*'

Find all nodes running CentOS in the production environment:

knife search node 'chef_environment:production AND platform:centos'

KNOWN BUGS

  • Searches against the client index return no results in most cases. (CHEF-2477)
  • Searches using the fuzzy match operator (~) produce an error. (CHEF-2478)

SEE ALSO

knife-ssh(1) http://wiki.opscode.com/display/chef/Attributes Lucene Query Parser Syntax

AUTHOR

Chef was written by Adam Jacob adam@opscode.com with many contributions from the community.

DOCUMENTATION

This manual page was written by Joshua Timberman joshua@opscode.com. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

CHEF

Knife is distributed with Chef. http://wiki.opscode.com/display/chef/Home

  1. Chef 11.8.2
  2. December 2013
  3. knife-search(1)
chef-11.8.2/distro/common/html/knife-environment.1.html0000644000004100000410000002616412254362222022774 0ustar www-datawww-data knife-environment(1) - Define cookbook policies for the environments in your infrastructure
  1. knife-environment(1)
  2. Chef Manual
  3. knife-environment(1)

NAME

knife-environment - Define cookbook policies for the environments in your infrastructure

SYNOPSIS

knife environment sub-command (options)

SUBCOMMANDS

Environment subcommands follow a basic create, read, update, delete (CRUD) pattern. The following subcommands are available:

CREATE

knife environment create environment (options)

-d, --description DESCRIPTION
The value of the description field.

Create a new environment object on the Chef Server. The envrionment will be opened in the text editor for editing prior to creation if the -n option is not present.

DELETE

knife environment delete environment (options)

Destroy an environment on the Chef Server. A prompt for confirmation will be displayed if the -y options is not given.

EDIT

knife environment edit environment (options)

Fetch environment and display it in the text editor for editing. The environment will be saved to the Chef Server when the editing session exits.

FROM FILE

knife environment from file file (options)

Create or update an environment from the JSON or Ruby format file. See format for the proper format of this file.

LIST

knife environment list (options) * -w, --with-uri: Show the resource URI for each environment

SHOW

knife environment show environment (options)

DESCRIPTION

Environments provide a means to apply policies to hosts in your infrastructure based on business function. For example, you may have a separate copy of your infrastructure called "dev" that runs the latest version of your application and should use the newest versions of your cookbooks when configuring systems, and a production instance of your infrastructure where you wish to update code and cookbooks in a more controlled fashion. In Chef, this function is implemented with environments.

Environments contain two major components: a set of cookbook version constraints and environment attributes.

SYNTAX

A cookbook version constraint is comprised of a cookbook name and a version constraint. The cookbook name is the name of a cookbook in your system, and the version constraint is a String describing the version(s) of that cookbook allowed in the environment. Only one version constraint is supported for a given cookbook name.

The exact syntax used to define a cookbook version constraint varies depending on whether you use the JSON format or the Ruby format. In the JSON format, the cookbook version constraints for an environment are represented as a single JSON object, like this:

{"apache2": ">= 1.5.0"}

In the Ruby format, the cookbook version contraints for an environment are represented as a Ruby Hash, like this:

{"apache2" => ">= 1.5.0"}

A version number is a String comprised of two or three digits separated by a dot (.) character, or in other words, strings of the form "major.minor" or "major.minor.patch". "1.2" and "1.2.3" are examples of valid version numbers. Version numbers containing more than three digits or alphabetic characters are not supported.

A version constraint String is composed of an operator and a version number. The following operators are available:

= VERSION
Equality. Only the exact version specified may be used.
> VERSION
Greater than. Only versions greater than VERSION may be used.
>= VERSION
Greater than or equal to. Only versions equal to VERSION or greater may be used.
< VERSION
Less than. Only versions less than VERSION may be used.
<= VERSION
Less than or equal to. Only versions lesser or equal to VERSION may be used.
~> VERSION
Pessimistic greater than. Depending on the number of components in the given VERSION, the constraint will be optimistic about future minor or patch revisions only. For example, ~> 1.1 will match any version less than 2.0 and greater than or equal to 1.1.0, whereas ~> 2.0.5 will match any version less than 2.1.0 and greater than or equal to 2.0.5.

FORMAT

The JSON format of an envioronment is as follows:

{
  "name": "dev",
  "description": "The development environment",
  "cookbook_versions": {
    "couchdb": "= 11.0.0"
  },
  "json_class": "Chef::Environment",
  "chef_type": "environment",
  "default_attributes": {
    "apache2": { "listen_ports": [ "80", "443" ] }
  },
  "override_attributes": {
    "aws_s3_bucket": "production"
  }
}

The Ruby format of an environment is as follows:

name "dev"
description "The development environment"
cookbook_versions  "couchdb" => "= 11.0.0"
default_attributes "apache2" => { "listen_ports" => [ "80", "443" ] }
override_attributes "aws_s3_bucket" => "production"

SEE ALSO

knife-node(1) knife-cookbook(1) knife-role(1) http://wiki.opscode.com/display/chef/Environments http://wiki.opscode.com/display/chef/Version+Constraints

AUTHOR

Chef was written by Adam Jacob adam@opscode.com with many contributions from the community.

DOCUMENTATION

This manual page was written by Daniel DeLeo dan@opscode.com. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

CHEF

Knife is distributed with Chef. http://wiki.opscode.com/display/chef/Home

  1. Chef 11.8.2
  2. December 2013
  3. knife-environment(1)
chef-11.8.2/distro/common/html/knife-data-bag.1.html0000644000004100000410000002327112254362222022064 0ustar www-datawww-data knife-data-bag(1) - Store arbitrary data on a Chef Server
  1. knife-data-bag(1)
  2. Chef Manual
  3. knife-data-bag(1)

NAME

knife-data-bag - Store arbitrary data on a Chef Server

SYNOPSIS

knife data bag sub-command (options)

DESCRIPTION

Data bags are stores of arbitrary JSON data. Each data bag is a collection that may contain many items. Data Bag Items are indexed by the Chef Server and can be searched via knife-search(1).

Data bags are available to all nodes configured by chef-client(8), and are therefore a convenient mechanism to store global information, such as lists of administrative accounts that should be configured on all hosts.

DATA BAG SUB-COMMANDS

CREATE

knife data bag create bag name [item id] (options)

-s, --secret SECRET
A secret key used to encrypt the data bag item. See encryption support below.
--secret-file SECRET_FILE
The path to a file containing the secret key to be used to encrypt the data bag item.

If item id is given, creates a new, empty data bag item and opens it for editing in your editor. The data bag will be created if it does not exist.

If item id is not given, the data bag will be created.

DELETE

knife data bag delete bag name [item id] (options)

Delete a data bag, or an item from a data bag.

EDIT

knife data bag edit bag name item id (options)

-s, --secret SECRET
A secret key used to encrypt the data bag item. See encryption support below.
--secret-file SECRET_FILE
The path to a file containing the secret key to be used to encrypt the data bag item.

Edit an item in a data bag.

FROM FILE

knife data bag from file bag name file (options)

knife data bag from file bag name file1 file2 file3 (options)

knife data bag from file bag name folder (options)

-s, --secret SECRET
A secret key used to encrypt the data bag item. See encryption support below.
--secret-file SECRET_FILE
The path to a file containing the secret key to be used to encrypt the data bag item.

Load a data bag item from a JSON file. If file is a relative or absolute path to the file, that file will be used. Otherwise, the file parameter is treated as the base name of a data bag file in a Chef repository, and knife will search for the file in ./data_bags/bag_name/file. For example knife data bag from file users dan.json would attempt to load the file ./data_bags/users/dan.json.

LIST

knife data bag list (options)

-w, --with-uri
Show corresponding URIs

Lists the data bags that exist on the Chef Server.

SHOW

knife data bag show BAG [ITEM] (options)

-s, --secret SECRET
A secret key used to encrypt the data bag item. See encryption support below.
--secret-file SECRET_FILE
The path to a file containing the secret key to be used to encrypt the data bag item.

Show a specific data bag or an item in a data bag. The output will be formatted according to the --format option.

ENCRYPTION SUPPORT

Data Bag Items may be encrypted to keep their contents secret. This may be desireable when storing sensitive information such as database passwords, API keys, etc.

Data Bag Item encryption uses the AES-256 CBC symmetric key algorithm.

CAVEATS: Keys are not encrypted; only values are encrypted. The "id" of a Data Bag Item is not encrypted, since it is used by Chef Server to store the item in its database. For example, given the following data bag item: {"id": "important_passwords", "secret_password": "opensesame"} The key "secret_password" will be visible to an evesdropper, but the value "opensesame" will be protected. Both the key "id" and its value "important_passwords" will be visible to an evesdropper.

Chef Server does not provide a secure mechanism for distributing encryption keys.

SEE ALSO

knife-search(1)

AUTHOR

Chef was written by Adam Jacob adam@opscode.com with many contributions from the community.

DOCUMENTATION

This manual page was written by Joshua Timberman joshua@opscode.com. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

CHEF

Knife is distributed with Chef. http://wiki.opscode.com/display/chef/Home

  1. Chef 11.8.2
  2. December 2013
  3. knife-data-bag(1)
chef-11.8.2/distro/common/html/chef-server-webui.8.html0000644000004100000410000002407012254362222022661 0ustar www-datawww-data chef-server-webui(8) - Start the Chef Server merb application slice providing Web User Interface (Management Console).
  1. chef-server-webui(8)
  2. Chef Manual
  3. chef-server-webui(8)

NAME

chef-server-webui - Start the Chef Server merb application slice providing Web User Interface (Management Console).

SYNOPSIS

chef-server-webui (options)

-u, --user USER
This flag is for having chef-server-webui run as a user other than the one currently logged in. Note: if you set this you must also provide a --group option for it to take effect.
-G, --group GROUP
This flag is for having chef-server-webui run as a group other than the one currently logged in. Note: if you set this you must also provide a --user option for it to take effect.
-d, --daemonize
This will run a single chef-server-webui in the background.
-N, --no-daemonize
This will allow you to run a cluster in console mode.
-c, --cluster-nodes NUM_MERBS
Number of merb daemons to run for chef-server-webui.
-I, --init-file FILE
File to use for initialization on load, defaults to config/init.rb.
-p, --port PORTNUM
Port to run chef-server-webui on, defaults to 4040. Additional nodes (-c) listen on incrementing port numbers.
-o, --socket-file FILE
Socket file to run chef-server-webui on, defaults to [Merb.root]/log/merb.sock. This is for web servers, like thin, that use sockets. Specify this only if you must.
-s, --socket SOCKNUM
Socket number to run chef-server-webui on, defaults to 0.
-n, --name NAME
Set the name of the application. This is used in the process title and log file names.
-P, --pid PIDFILE
PID file, defaults to [Merb.root]/log/merb.main.pid for the master process and[Merb.root]/log/merb.[port number].pid for worker processes. For clusters, use %s to specify where in the file chef-server-webui should place the port number. For instance: -P myapp.%s.pid.
-h, --host HOSTNAME
Host to bind to (default is 0.0.0.0).
-m, --merb-root PATH_TO_APP_ROOT
The path to the Merb.root for the app you want to run (default is current working directory).
-a, --adapter ADAPTER
The rack adapter to use to run chef-server-webui (default is mongrel) [mongrel, emongrel, thin, ebb, fastcgi, webrick].
-R, --rackup FILE
Load an alternate Rack config file (default is config/rack.rb).
-i, --irb-console
This flag will start chef-server-webui in irb console mode. All your models and other classes will be available for you in an irb session.
-S, --sandbox
This flag will enable a sandboxed irb console. If your ORM supports transactions, all edits will be rolled back on exit.
-l, --log-level LEVEL
Log levels can be set to any of these options: debug < info < warn < error < fatal (default is info).
-L, --log LOGFILE
A string representing the logfile to use. Defaults to [Merb.root]/log/merb.[main].log for the master process and [Merb.root]/log/merb[port number].logfor worker processes.
-e, --environment STRING
Environment to run Merb under [development, production, testing] (default is development).
-r, --script-runner ['RUBY CODE'| FULL_SCRIPT_PATH]
Command-line option to run scripts and/or code in the chef-server-webui app.
-K, -graceful PORT or all
Gracefully kill chef-server-webui proceses by port number. Use chef-server -K all to gracefully kill all merbs.
-k, --kill PORT
Force kill one merb worker by port number. This will cause the worker to be respawned.
--fast-deploy
Reload the code, but not yourinit.rb or gems.
-X, --mutex on/off
This flag is for turning the mutex lock on and off.
-D, --debugger
Run chef-server-webui using rDebug.
-V, --verbose
Print extra information.
-C, --console-trap
Enter an irb console on ^C.
-?, -H, --help
Show this help message.

DESCRIPTION

The Chef Server WebUI (Management Console) is a Merb application slice. The default listen port is 4040.

The Management Console is Chef Server's web interface. Nodes, roles, cookbooks, data bags, and API clients can be managed through the Management Console. Search can also be done on the console.

In order to start using the Management Console, you need to first create a user or change the default password on the "admin" user.

The default credentials are:

  • Username: admin
  • Password: p@ssw0rd1

SEE ALSO

Full documentation for Chef and chef-server-webui (Management Console) is located on the Chef wiki, http://wiki.opscode.com/display/chef/Home.

AUTHOR

Chef was written by Adam Jacob adam@ospcode.com of Opscode (http://www.opscode.com), with contributions from the community. This manual page was written by Joshua Timberman joshua@opscode.com with help2man for the Debian project (but may be used by others). Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

On Debian systems, the complete text of the Apache 2.0 License can be found in /usr/share/common-licenses/Apache-2.0.

  1. Chef 11.8.2
  2. December 2013
  3. chef-server-webui(8)
chef-11.8.2/distro/common/html/chef-client.8.html0000644000004100000410000001632612254362222021525 0ustar www-datawww-data chef-client(8) - Runs a client node connecting to a chef-server.
  1. chef-client(8)
  2. Chef Manual
  3. chef-client(8)

NAME

chef-client - Runs a client node connecting to a chef-server.

SYNOPSIS

chef-client (options)

-S, --server CHEFSERVERURL
The chef server URL
-c, --config CONFIG
The configuration file to use
-d, --daemonize
Daemonize the process
-g, --group GROUP
Group to set privilege to
-i, --interval SECONDS
Run chef-client periodically, in seconds
-j, --json-attributes JSON_ATTRIBS
Load attributes from a JSON file or URL
-E, --environment ENVIRONMENT
Set the Chef Environment on the node
-l, --log_level LEVEL
Set the log level (debug, info, warn, error, fatal)
-L, --logfile LOGLOCATION
Set the log file location, defaults to STDOUT - recommended for daemonizing
-N, --node-name NODE_NAME
The node name for this client
-o, --override-runlist
Replace current run list with specified items
-K, --validation_key KEY_FILE
Set the validation key file location, used for registering new clients
-k, --client_key KEY_FILE
Set the client key file location
-s, --splay SECONDS
The splay time for running at intervals, in seconds
-u, --user USER
User to set privilege to
-P, --pid PIDFILE
Set the PID file location, defaults to /tmp/chef-client.pid
--once
Cancel any interval or splay options, run chef once and exit
-v, --version
Show chef version
-h, --help
Show this message

DESCRIPTION

The Chef Client is where almost all of the work in Chef is done. It communicates with the Chef Server via REST, authenticates via Signed Header Authentication, and compiles and executes Cookbooks.

A Chef Client does work on behalf of a Node. A single Chef Client can run recipes for multiple Nodes.

Clients are where all the action happens - the Chef Server and Chef Expander are largely services that exist only to provide the Client with information.

SEE ALSO

Full documentation for Chef and chef-client is located on the Chef wiki, http://wiki.opscode.com/display/chef/Home.

AUTHOR

Chef was written by Adam Jacob adam@ospcode.com of Opscode (http://www.opscode.com), with contributions from the community. This manual page was written by Joshua Timberman joshua@opscode.com with help2man. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

On Debian systems, the complete text of the Apache 2.0 License can be found in /usr/share/common-licenses/Apache-2.0.

  1. Chef 11.8.2
  2. December 2013
  3. chef-client(8)
chef-11.8.2/distro/common/html/knife-node.1.html0000644000004100000410000002457512254362222021361 0ustar www-datawww-data knife-node(1) - Manage the hosts in your infrastructure
  1. knife-node(1)
  2. Chef Manual
  3. knife-node(1)

NAME

knife-node - Manage the hosts in your infrastructure

SYNOPSIS

knife node sub-command (options)

DESCRIPTION

Nodes are data structures that represent hosts configured with Chef. Nodes have a name, a String that uniquely identifies the node, attributes, a nested Hash of properties that describe how the host should be configured, a chef_environment, a String representing the environment to which the node belongs, and a run_list, an ordered list of recipes or roles that chef-client should apply when configuring a host.

When a host communicates with a Chef Server, it authenticates using its node_name for identification and signs its reqests with a private key. The Server validates the request by looking up a client object with a name identical to the node_name submitted with the request and verifes the signature using the public key for that client object. NOTE that the client is a different object in the system. It is associated with a node by virtue of having a matching name.

By default chef-client(8) will create a node using the FQDN of the host for the node name, though this may be overridden by configuration settings.

NODE SUB-COMMANDS

The following node subcommands are available:

BULK DELETE

knife node bulk delete regex (options)

Deletes nodes for which the name matches the regular expression regex on the Chef Server. The regular expression should be given in quotes, and should not be surrounded with forward slashes (as is typical of regular expression literals in scripting languages).

CREATE

knife node create name (options)

Create a new node. Unless the --disable-editing option is given, an empty node object will be created and displayed in your text editor. If the editor exits with a successful exit status, the node data will be posted to the Chef Server to create the node.

DELETE

knife node delete name (options)

Deletes the node identified by name on the Chef Server.

EDIT

knife node edit name (options)

-a, --all
Display all node data in the editor. By default, default, override, and automatic attributes are not shown.

Edit the node identified by name. Like knife node create, the node will be displayed in your text editor unless the -n option is present.

FROM FILE

knife node from file file (options)

Create a node from a JSON format file.

LIST

knife node list (options)

-w, --with-uri
Show corresponding URIs

List all nodes.

RUN_LIST ADD

knife node run_list add name run list item (options)

-a, --after ITEM
Place the ENTRY in the run list after ITEM

Add the run list item to the node's run_list. See Run list

RUN_LIST REMOVE

knife node run_list remove node name run list item (options)

Remove the run list item from the node's run_list.

SHOW

knife node show node name (options)

-a, --attribute [ATTR]
Show only one attribute
-r, --run-list
Show only the run list
-F, --format FORMAT
Display the node in a different format.
-m, --medium
Display more, but not all, of the node's data when using the default summary format

Displays the node identified by node name on stdout.

RUN LIST ITEM FORMAT

Run list items may be either roles or recipes. When adding a role to a run list, the correct syntax is "role[ROLE_NAME]"

When adding a recipe to a run list, there are several valid formats:

Fully Qualified Format
"recipe[COOKBOOK::RECIPE_NAME]", for example, "recipe[chef::client]"
Cookbook Recipe Format
For brevity, the recipe part of the fully qualified format may be omitted, and recipes specified as "COOKBOOK::RECIPE_NAME", e.g., "chef::client"
Default Recipe Format
When adding the default recipe of a cookbook to a run list, the recipe name may be omitted as well, e.g., "chef::default" may be written as just "chef"

SEE ALSO

knife-client(1) knife-search(1) knife-role(1)

AUTHOR

Chef was written by Adam Jacob adam@opscode.com with many contributions from the community.

DOCUMENTATION

This manual page was written by Joshua Timberman joshua@opscode.com. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

CHEF

Knife is distributed with Chef. http://wiki.opscode.com/display/chef/Home

  1. Chef 11.8.2
  2. December 2013
  3. knife-node(1)
chef-11.8.2/distro/common/html/knife-bootstrap.1.html0000644000004100000410000002553512254362222022446 0ustar www-datawww-data knife-bootstrap(1) - Install Chef Client on a remote host
  1. knife-bootstrap(1)
  2. Chef Manual
  3. knife-bootstrap(1)

NAME

knife-bootstrap - Install Chef Client on a remote host

SYNOPSIS

knife bootstrap (options)

-i, --identity-file IDENTITY_FILE
The SSH identity file used for authentication
-N, --node-name NAME
The Chef node name for your new node
-P, --ssh-password PASSWORD
The ssh password
-x, --ssh-user USERNAME
The ssh username
-p, --ssh-port PORT
The ssh port
--bootstrap-version VERSION
The version of Chef to install
--bootstrap-proxy PROXY_URL
The proxy server for the node being bootstrapped
--prerelease
Install pre-release Chef gems
-r, --run-list RUN_LIST
Comma separated list of roles/recipes to apply
--template-file TEMPLATE
Full path to location of template to use
--sudo
Execute the bootstrap via sudo
-d, --distro DISTRO
Bootstrap a distro using a template
--[no-]host-key-verify
Enable host key verification, which is the default behavior.
--hint HINT_NAME[=HINT_FILE]
Provide the name of a hint (with option JSON file) to set for use by Ohai plugins.

DESCRIPTION

Performs a Chef Bootstrap on the target node. The goal of the bootstrap is to get Chef installed on the target system so it can run Chef Client with a Chef Server. The main assumption is a baseline OS installation exists. This sub-command is used internally by some cloud computing plugins.

The bootstrap sub-command supports supplying a template to perform the bootstrap steps. If the distro is not specified (via -d or --distro option), an Ubuntu 10.04 host bootstrapped with RubyGems is assumed. The DISTRO value corresponds to the base filename of the template, in other words DISTRO.erb. A template file can be specified with the --template-file option in which case the DISTRO is not used. The sub-command looks in the following locations for the template to use:

  • bootstrap directory in the installed Chef Knife library.
  • bootstrap directory in the $PWD/.chef.
  • bootstrap directory in the users $HOME/.chef.

The default bootstrap templates are scripts that get copied to the target node (FQDN). The following distros are supported:

  • centos5-gems
  • fedora13-gems
  • ubuntu10.04-gems
  • ubuntu10.04-apt

The gems installations will use RubyGems 1.3.6 and Chef installed as a gem. The apt installation will use the Opscode APT repository.

In addition to handling the software installation, these bootstrap templates do the following:

  • Write the validation.pem per the local knife configuration.
  • Write a default config file for Chef (/etc/chef/client.rb) using values from the knife.rb.
  • Create a JSON attributes file containing the specified run list and run Chef.

In the case of the RubyGems, the client.rb will be written from scratch with a minimal set of values; see EXAMPLES. In the case of APT Package installation, client.rb will have the validation_client_name appended if it is not set to chef-validator (default config value), and the node_name will be added if chef_node_name option is specified.

When this is complete, the bootstrapped node will have:

  • Latest Chef version installed from RubyGems or APT Packages from Opscode. This may be a later version than the local system.
  • Be validated with the configured Chef Server.
  • Have run Chef with its default run list if one is specfied.

Additional custom bootstrap templates can be created and stored in .chef/bootstrap/DISTRO.erb, replacing DISTRO with the value passed with the -d or --distro option. See EXAMPLES for more information.

EXAMPLES

Setting up a custom bootstrap is fairly straightforward. Create a .chef/bootstrap directory in your Chef Repository or in $HOME/.chef/bootstrap. Then create the ERB template file.

mkdir ~/.chef/bootstrap
vi ~/.chef/bootstrap/debian5.0-apt.erb

For example, to create a new bootstrap template that should be used when setting up a new Debian node. Edit the template to run the commands, set up the validation certificate and the client configuration file, and finally to run chef-client on completion. The bootstrap template can be called with:

knife bootstrap mynode.example.com --template-file ~/.chef/bootstrap/debian5.0-apt.erb

Or,

knife bootstrap mynode.example.com --distro debian5.0-apt

The --distro parameter will automatically look in the ~/.chef/bootstrap directory for a file named debian5.0-apt.erb.

Templates provided by the Chef installation are located in BASEDIR/lib/chef/knife/bootstrap/*.erb, where BASEDIR is the location where the package or Gem installed the Chef client libraries.

BUGS

knife bootstrap is not capable of bootstrapping multiple hosts in parallel.

The bootstrap script is passed as an argument to sh(1) on the remote system, so sensitive information contained in the script will be visible to other users via the process list using tools such as ps(1).

SEE ALSO

knife-ssh(1)

AUTHOR

Chef was written by Adam Jacob adam@opscode.com with many contributions from the community.

DOCUMENTATION

This manual page was written by Joshua Timberman joshua@opscode.com. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

CHEF

Knife is distributed with Chef. http://wiki.opscode.com/display/chef/Home

  1. Chef 11.8.2
  2. December 2013
  3. knife-bootstrap(1)
chef-11.8.2/distro/common/html/chef-expanderctl.8.html0000644000004100000410000001410712254362222022553 0ustar www-datawww-data chef-expanderctl(8) - management program for chef-expander
  1. chef-expanderctl(8)
  2. Chef Manual
  3. chef-expanderctl(8)

NAME

chef-expanderctl - management program for chef-expander

SYNOPSIS

chef-expanderctl COMMAND

Commands:

help
Show help message
queue-depth
display the aggregate queue backlog
queue-status
show the backlog and consumer count for each vnode queue
node-status
show the status of the nodes in the cluster
log-level
sets the log level of all nodes in the cluster

DESCRIPTION

Chef-expanderctl is a management program that allows you to get status information or change the logging verbosity (without restarting). chef-expanderctl has the following commands:

  • chef-expanderctl help prints usage.
  • chef-expanderctl queue-depth Shows the total number of messages in the queues.
  • chef-expanderctl queue-status Show the number of messages in each queue. This is mainly of use when debugging a Chef Expander cluster.
  • chef-expanderctl log-level LEVEL Sets the log level on a running Chef Expander or cluster. If you suspect that a worker process is stuck, as long as you are using clustered operation, you can simply kill the worker process and it will be restarted by the master process.

SEE ALSO

chef-expander-cluster(8) chef-solr(8)

Full documentation for Chef and chef-server is located on the Chef wiki, http://wiki.opscode.com/display/chef/Home.

AUTHOR

Chef was written by Adam Jacob adam@ospcode.com of Opscode (http://www.opscode.com), with contributions from the community. This manual page was created by Nuo Yan nuo@opscode.com. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

On Debian systems, the complete text of the Apache 2.0 License can be found in /usr/share/common-licenses/Apache-2.0.

  1. Chef 11.8.2
  2. December 2013
  3. chef-expanderctl(8)
chef-11.8.2/distro/common/html/knife-cookbook-site.1.html0000644000004100000410000002363412254362222023177 0ustar www-datawww-data knife-cookbook-site(1) - Install and update open source cookbooks
  1. knife-cookbook-site(1)
  2. Chef Manual
  3. knife-cookbook-site(1)

NAME

knife-cookbook-site - Install and update open source cookbooks

SYNOPSIS

knife cookbook site sub-command (options)

COOKBOOK SITE SUB-COMMANDS

knife cookbook site provides the following subcommands:

INSTALL

cookbook site install COOKBOOK [VERSION] (options)

-D, --skip-dependencies
Skip automatic installation of dependencies.
-o, --cookbook-path PATH
Install cookbooks to PATH
-B, --branch BRANCH
Default branch to work with [defaults to master]

Uses git(1) version control in conjunction with the cookbook site to install community contributed cookbooks to your local cookbook repository. Running knife cookbook site install does the following:

  1. A new "pristine copy" branch is created in git for tracking the upstream;
  2. All existing cookbooks are removed from the branch;
  3. The cookbook is downloaded from the cookbook site in tarball form;
  4. The downloaded cookbook is untarred, and its contents commited via git;
  5. The pristine copy branch is merged into the master branch.

By installing cookbook with this process, you can locally modify the upstream cookbook in your master branch and let git maintain your changes as a separate patch. When an updated upstream version becomes available, you will be able to merge the upstream changes while maintaining your local modifications.

Unless --skip-dependencies is specified, the process is applied recursively to all the cookbooks COOKBOOK depends on (via metadata dependencies).

DOWNLOAD

knife cookbook site download COOKBOOK [VERSION] (options)

-f, --file FILE
The filename to write to
--force
Force download deprecated cookbook

Downloads a specific cookbook from the Community site, optionally specifying a certain version.

LIST

knife cookbook site list (options)

-w, --with-uri
Show corresponding URIs

Lists available cookbooks from the Community site.

knife cookbook site search QUERY (options)

Searches for available cookbooks matching the specified query.

SHARE

knife cookbook site share COOKBOOK CATEGORY (options)

-k, --key KEY
API Client Key
-u, --user USER
API Client Username
-o, --cookbook-path PATH:PATH
A colon-separated path to look for cookbooks in

Uploads the specified cookbook using the given category to the Opscode cookbooks site. Requires a login user and certificate for the Opscode Cookbooks site. By default, knife will use the username and API key you've configured in your configuration file; otherwise you must explicitly set these values on the command line or use an alternate configuration file.

UNSHARE

knife cookbook site unshare COOKBOOK

Stops sharing the specified cookbook on the Opscode cookbooks site.

SHOW

knife cookbook site show COOKBOOK [VERSION] (options)

Shows information from the site about a particular cookbook.

DESCRIPTION

The cookbook site, http://community.opscode.com/, is a cookbook distribution service operated by Opscode. This service provides users with a central location to publish cookbooks for sharing with other community members.

knife cookbook site commands provide an interface to the cookbook site's HTTP API. For commands that read data from the API, no account is required. In order to upload cookbooks using the knife cookbook site share command, you must create an account on the cookbook site and configure your credentials via command line option or in your knife configuration file.

EXAMPLES

Uploading cookbooks to the Opscode cookbooks site:

knife cookbook site share example Other -k ~/.chef/USERNAME.pem -u USERNAME

SEE ALSO

knife-cookbook(1) http://community.opscode.com/cookbooks

AUTHOR

Chef was written by Adam Jacob adam@opscode.com with many contributions from the community.

DOCUMENTATION

This manual page was written by Joshua Timberman joshua@opscode.com. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

CHEF

Knife is distributed with Chef. http://wiki.opscode.com/display/chef/Home

  1. Chef 11.8.2
  2. December 2013
  3. knife-cookbook-site(1)
chef-11.8.2/distro/common/html/chef-server.8.html0000644000004100000410000002373712254362222021561 0ustar www-datawww-data chef-server(8) - Start the Chef Server merb application slice.
  1. chef-server(8)
  2. Chef Manual
  3. chef-server(8)

NAME

chef-server - Start the Chef Server merb application slice.

SYNOPSIS

chef-server (options)

-u, --user USER
This flag is for having chef-server-webui run as a user other than the one currently logged in. Note: if you set this you must also provide a --group option for it to take effect.
-G, --group GROUP
This flag is for having chef-server-webui run as a group other than the one currently logged in. Note: if you set this you must also provide a --user option for it to take effect.
-d, --daemonize
This will run a single chef-server-webui in the background.
-N, --no-daemonize
This will allow you to run a cluster in console mode.
-c, --cluster-nodes NUM_MERBS
Number of merb daemons to run for chef-server-webui.
-I, --init-file FILE
File to use for initialization on load, defaults to config/init.rb.
-p, --port PORTNUM
Port to run chef-server-webui on, defaults to 4040. Additional nodes (-c) listen on incrementing port numbers.
-o, --socket-file FILE
Socket file to run chef-server-webui on, defaults to [Merb.root]/log/merb.sock. This is for web servers, like thin, that use sockets. Specify this only if you must.
-s, --socket SOCKNUM
Socket number to run chef-server-webui on, defaults to 0.
-n, --name NAME
Set the name of the application. This is used in the process title and log file names.
-P, --pid PIDFILE
PID file, defaults to [Merb.root]/log/merb.main.pid for the master process and[Merb.root]/log/merb.[port number].pid for worker processes. For clusters, use %s to specify where in the file chef-server-webui should place the port number. For instance: -P myapp.%s.pid.
-h, --host HOSTNAME
Host to bind to (default is 0.0.0.0).
-m, --merb-root PATH_TO_APP_ROOT
The path to the Merb.root for the app you want to run (default is current working directory).
-a, --adapter ADAPTER
The rack adapter to use to run chef-server-webui (default is mongrel) [mongrel, emongrel, thin, ebb, fastcgi, webrick].
-R, --rackup FILE
Load an alternate Rack config file (default is config/rack.rb).
-i, --irb-console
This flag will start chef-server-webui in irb console mode. All your models and other classes will be available for you in an irb session.
-S, --sandbox
This flag will enable a sandboxed irb console. If your ORM supports transactions, all edits will be rolled back on exit.
-l, --log-level LEVEL
Log levels can be set to any of these options: debug < info < warn < error < fatal (default is info).
-L, --log LOGFILE
A string representing the logfile to use. Defaults to [Merb.root]/log/merb.[main].log for the master process and [Merb.root]/log/merb[port number].logfor worker processes.
-e, --environment STRING
Environment to run Merb under [development, production, testing] (default is development).
-r, --script-runner ['RUBY CODE'| FULL_SCRIPT_PATH]
Command-line option to run scripts and/or code in the chef-server-webui app.
-K, -graceful PORT or all
Gracefully kill chef-server-webui proceses by port number. Use chef-server -K all to gracefully kill all merbs.
-k, --kill PORT
Force kill one merb worker by port number. This will cause the worker to be respawned.
--fast-deploy
Reload the code, but not yourinit.rb or gems.
-X, --mutex on/off
This flag is for turning the mutex lock on and off.
-D, --debugger
Run chef-server-webui using rDebug.
-V, --verbose
Print extra information.
-C, --console-trap
Enter an irb console on ^C.
-?, -H, --help
Show this help message.

DESCRIPTION

The Chef Server provides a central point for the distribution of Cookbooks, management and authentication of Nodes, and the use of Search. It provides a REST API.

The API service is what clients use to interact with the server to manage node configuration in Chef. By default, the service is started on port 4000 as a Merb application slice running with the thin server adapter.

The two methods of interaction with the API for humans are the command-line tool Knife and the Management Console. The Chef Client library is used for interacting with the API for client nodes.

SEE ALSO

chef-client(8) chef-server-webui(8) knife(1)

Full documentation for Chef and chef-server is located on the Chef wiki, http://wiki.opscode.com/display/chef/Home.

AUTHOR

Chef was written by Adam Jacob adam@ospcode.com of Opscode (http://www.opscode.com), with contributions from the community. This manual page was written by Joshua Timberman joshua@opscode.com with help2man. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License.

On Debian systems, the complete text of the Apache 2.0 License can be found in /usr/share/common-licenses/Apache-2.0.

  1. Chef 11.8.2
  2. December 2013
  3. chef-server(8)
chef-11.8.2/distro/common/man/0000755000004100000410000000000012254362222016107 5ustar www-datawww-datachef-11.8.2/distro/common/man/man8/0000755000004100000410000000000012254362222016752 5ustar www-datawww-datachef-11.8.2/distro/common/man/man8/chef-solo.80000644000004100000410000001471512254362222020732 0ustar www-datawww-data.TH "CHEF-SOLO" "8" "Chef 11.8.0" "" "chef-solo" .SH NAME chef-solo \- The man page for the chef-solo command line tool. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp chef\-solo is an open source version of the chef\-client that allows using cookbooks with nodes without requiring access to a server. chef\-solo runs locally and requires that a cookbook (and any of its dependencies) be on the same physical disk as the node. chef\-solo is a limited\-functionality version of the chef\-client and \fBdoes not support\fP the following: .INDENT 0.0 .IP \(bu 2 Node data storage .IP \(bu 2 Search indexes .IP \(bu 2 Centralized distribution of cookbooks .IP \(bu 2 A centralized API that interacts with and integrates infrastructure components .IP \(bu 2 Authentication or authorization .IP \(bu 2 Persistent attributes .UNINDENT .sp The chef\-solo executable can be run as a command\-line tool. .SH OPTIONS .sp This command has the following syntax: .sp .nf .ft C chef\-solo OPTION VALUE OPTION VALUE ... .ft P .fi .sp This command has the following options: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-d\fP, \fB\-\-daemonize\fP Indicates that the executable will be run as a daemon. This option is only available on machines that run in UNIX or Linux environments. For machines that are running Microsoft Windows that require similar functionality, use the \fBchef\-client::service\fP recipe in the \fBchef\-client\fP cookbook: \fI\%http://community.opscode.com/cookbooks/chef-client\fP. This will install a chef\-client service under Microsoft Windows using the Windows Service Wrapper. .TP .B \fB\-f\fP, \fB\-\-[no\-]fork\fP Indicates that a chef\-client run will be contained in a secondary process with dedicated RAM. When the chef\-client run is complete the RAM will be returned to the master process. This option helps ensure that a chef\-client will use a steady amount of RAM over time because the master process will not run recipes. This option will also help prevent memory leaks (such as those that can be introduced by the code contained within a poorly designed cookbook). Use \fB\-\-no\-fork\fP to disable running the chef\-client in fork node. Default value: \fB\-\-fork\fP. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-\-force\-formatter\fP Indicates that formatter output will be used instead of logger output. .TP .B \fB\-\-force\-logger\fP Indicates that logger output will be used instead of formatter output. .TP .B \fB\-g GROUP\fP, \fB\-\-group GROUP\fP The name of the group that owns a process. This is required when starting any executable as a daemon. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-i SECONDS\fP, \fB\-\-interval SECONDS\fP The frequency (in seconds) at which the chef\-client runs. This value is configured for the chef\-client application run time, rather than in \fBChef::Config\fP. .TP .B \fB\-j PATH\fP, \fB\-\-json\-attributes PATH\fP The path to a file that contains JSON data. Use this option to override attributes that are set from other locations, such as from within a cookbook or by a role. .TP .B \fB\-l LEVEL\fP, \fB\-\-log_level LEVEL\fP The level of logging that will be stored in a log file: \fBdebug\fP, \fBinfo\fP, \fBwarn\fP, \fBerror\fP, or \fBfatal\fP. .TP .B \fB\-L LOGLOCATION\fP, \fB\-\-logfile c\fP The location in which log file output files will be saved. If this location is set to something other than \fBSTDOUT\fP, standard output logging will still be performed (otherwise there would be no output other than to a file). This is recommended when starting any executable as a daemon. .TP .B \fB\-\-[no\-]color\fP Indicates that color will not be used in the output. Default setting: \fB\-\-color\fP. .TP .B \fB\-N NODE_NAME\fP, \fB\-\-node\-name NODE_NAME\fP The name of the node. .TP .B \fB\-o RUN_LIST_ITEM\fP, \fB\-\-override\-runlist RUN_LIST_ITEM\fP Replace the current run list with the specified items. .TP .B \fB\-r RECIPE_URL\fP, \fB\-\-recipe\-url RECIPE_URL\fP The URL location from which a remote cookbook tar.gz will be downloaded. .TP .B \fB\-s SECONDS\fP, \fB\-\-splay SECONDS\fP A number (in seconds) to add to the \fBinterval\fP that is used to determine the frequency of chef\-client runs. This number can help prevent server load when there are many clients running at the same time. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user that owns a process. This is required when starting any executable as a daemon. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-W\fP, \fB\-\-why\-run\fP Indicates that the executable will be run in why\-run mode, which is a type of chef\-client run that does everything except modify the system. Use why\-run mode to understand why the chef\-client makes the decisions that it makes and to learn more about the current and proposed state of the system. .UNINDENT .SH EXAMPLES .sp \fBUse a URL\fP .sp .nf .ft C $ chef\-solo \-c ~/solo.rb \-j ~/node.json \-r http://www.example.com/chef\-solo.tar.gz .ft P .fi .sp where \fB\-r\fP uses the \fBremote_file\fP resource to retrieve the tar.gz archive into the \fBfile_cache_path\fP, and then extract it to \fBcookbooks_path\fP. .sp \fBUse a directory\fP .sp .nf .ft C $ chef\-solo \-c ~/solo.rb \-j ~/node.json .ft P .fi .sp where the \fB\-r URL\fP option is not used. chef\-solo will look in the solo.rb file to determine the directory in which cookbooks are located. .sp \fBUse a URL for cookbook and JSON data\fP .sp .nf .ft C $ chef\-solo \-c ~/solo.rb \-j http://www.example.com/node.json \-r http://www.example.com/chef\-solo.tar.gz .ft P .fi .sp where \fB\-r\fP corresponds to \fBrecipe_url\fP and \fB\-j\fP corresponds to \fBjson_attribs\fP, both of which are configuration options in solo.rb. .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man8/chef-client.80000644000004100000410000002513212254362222021227 0ustar www-datawww-data.TH "CHEF-CLIENT" "8" "Chef 11.8.0" "" "chef-client" .SH NAME chef-client \- The man page for the chef-client command line tool. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp A chef\-client is an agent that runs locally on every node that is registered with the server. When a chef\-client is run, it will perform all of the steps that are required to bring the node into the expected state, including: .INDENT 0.0 .IP \(bu 2 Registering and authenticating the node with the server .IP \(bu 2 Building the node object .IP \(bu 2 Synchronizing cookbooks .IP \(bu 2 Compiling the resource collection by loading each of the required cookbooks, including recipes, attributes, and all other dependencies .IP \(bu 2 Taking the appropriate and required actions to configure the node .IP \(bu 2 Looking for exceptions and notifications, handling each as required .UNINDENT .sp The chef\-client executable can be run as a command\-line tool. .IP Note A client.rb file is used to specify the configuration details for the chef\-client. This file is the default configuration file and is loaded every time the chef\-client executable is run. The chef\-client executable can be run as a daemon. On UNIX\- and Linux\-based machines, the configuration file is located at: /etc/chef/client.rb. On Microsoft Windows machines, the configuration file is located at C:chefclient.rb. .RE .SH OPTIONS .sp This command has the following syntax: .sp .nf .ft C chef\-client OPTION VALUE OPTION VALUE ... .ft P .fi .sp This command has the following options: .INDENT 0.0 .TP .B \fB\-A\fP, \fB\-\-fatal\-windows\-admin\-check\fP Indicates that a chef\-client run should fail if the chef\-client does not have administrator privileges in Microsoft Windows. .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-d\fP, \fB\-\-daemonize\fP Indicates that the executable will be run as a daemon. This option is only available on machines that run in UNIX or Linux environments. For machines that are running Microsoft Windows that require similar functionality, use the \fBchef\-client::service\fP recipe in the \fBchef\-client\fP cookbook: \fI\%http://community.opscode.com/cookbooks/chef-client\fP. This will install a chef\-client service under Microsoft Windows using the Windows Service Wrapper. .TP .B \fB\-E ENVIRONMENT_NAME\fP, \fB\-\-environment ENVIRONMENT_NAME\fP The name of the environment. .TP .B \fB\-f\fP, \fB\-\-fork\fP Indicates that a chef\-client run will be contained in a secondary process with dedicated RAM. When the chef\-client run is complete the RAM will be returned to the master process. This option helps ensure that a chef\-client will use a steady amount of RAM over time because the master process will not run recipes. This option will also help prevent memory leaks (such as those that can be introduced by the code contained within a poorly designed cookbook). Use \fB\-\-no\-fork\fP to disable running the chef\-client in fork node. Default value: \fB\-\-fork\fP. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-\-force\-formatter\fP Indicates that formatter output will be used instead of logger output. .TP .B \fB\-\-force\-logger\fP Indicates that logger output will be used instead of formatter output. .TP .B \fB\-g GROUP\fP, \fB\-\-group GROUP\fP The name of the group that owns a process. This is required when starting any executable as a daemon. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-i SECONDS\fP, \fB\-\-interval SECONDS\fP The frequency (in seconds) at which the chef\-client runs. This value is configured for the chef\-client application run time, rather than in \fBChef::Config\fP. Default value: \fB1800\fP. .TP .B \fB\-j PATH\fP, \fB\-\-json\-attributes PATH\fP The path to a file that contains JSON data. Use this option to override attributes that are set from other locations, such as from within a cookbook or by a role. .TP .B \fB\-k KEY_FILE\fP, \fB\-\-client_key KEY_FILE\fP The location of the file which contains the client key. Default value: \fB/etc/chef/client.pem\fP. .TP .B \fB\-K KEY_FILE\fP, \fB\-\-validation_key KEY_FILE\fP The location of the file which contains the key used when a chef\-client is registered with a server. A validation key is signed using the \fBvalidation_client_name\fP for authentication. Default value: \fB/etc/chef/validation.pem\fP. .TP .B \fB\-l LEVEL\fP, \fB\-\-log_level LEVEL\fP The level of logging that will be stored in a log file: \fBdebug\fP, \fBinfo\fP, \fBwarn\fP, \fBerror\fP, or \fBfatal\fP. .TP .B \fB\-L LOGLOCATION\fP, \fB\-\-logfile c\fP The location in which log file output files will be saved. If this location is set to something other than \fBSTDOUT\fP, standard output logging will still be performed (otherwise there would be no output other than to a file). This is recommended when starting any executable as a daemon. Default value: \fBSTDOUT\fP. .TP .B \fB\-\-[no\-]color\fP Indicates that color will not be used in the output. Default setting: \fB\-\-color\fP. .TP .B \fB\-N NODE_NAME\fP, \fB\-\-node\-name NODE_NAME\fP The name of the node. .TP .B \fB\-o RUN_LIST_ITEM\fP, \fB\-\-override\-runlist RUN_LIST_ITEM\fP Replace the current run list with the specified items. .TP .B \fB\-\-once\fP Indicates that the chef\-client is run once and that interval and splay options are cancelled. .TP .B \fB\-P PID_FILE\fP, \fB\-\-pid PID_FILE\fP The location in which a process identification number (pid) is saved. An executable, when started as a daemon, will write the pid to the specified file. Default value: \fB/tmp/name\-of\-executable.pid\fP. .TP .B \fB\-R\fP, \fB\-\-enable\-reporting\fP Indicates that data collection reporting is enabled during a chef\-client run. .TP .B \fB\-s SECONDS\fP, \fB\-\-splay SECONDS\fP A number (in seconds) to add to the \fBinterval\fP that is used to determine the frequency of chef\-client runs. This number can help prevent server load when there are many clients running at the same time. .TP .B \fB\-S CHEF_SERVER_URL\fP, \fB\-\-server CHEF_SERVER_URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user that owns a process. This is required when starting any executable as a daemon. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-W\fP, \fB\-\-why\-run\fP Indicates that the executable will be run in why\-run mode, which is a type of chef\-client run that does everything except modify the system. Use why\-run mode to understand why the chef\-client makes the decisions that it makes and to learn more about the current and proposed state of the system. .TP .B \fB\-z\fP, \fB\-\-local\-mode\fP Indicates that the chef\-client will be run in local mode, which allows all commands that work against the server to also work against the local chef\-repo. .UNINDENT .SH RUN WITH ELEVATED PRIVILEGES .sp The chef\-client may need to be run with elevated privileges in order to get a recipe to converge correctly. On UNIX and UNIX\-like operating systems this can be done by running the command as root. On Microsoft Windows this can be done by running the command prompt as an administrator. .SS Linux .sp On Linux, the following error sometimes occurs when the permissions used to run the chef\-client are incorrect: .sp .nf .ft C $ chef\-client [Tue, 29 Nov 2011 19:46:17 \-0800] INFO: *** Chef 10.X.X *** [Tue, 29 Nov 2011 19:46:18 \-0800] WARN: Failed to read the private key /etc/chef/client.pem: # .ft P .fi .sp This can be resolved by running the command as root. There are a few ways this can be done: .INDENT 0.0 .IP \(bu 2 Log in as root and then run the chef\-client .IP \(bu 2 Use \fBsu\fP to become the root user, and then run the chef\-client. For example: .INDENT 2.0 .INDENT 3.5 .sp .nf .ft C $ su .ft P .fi .UNINDENT .UNINDENT .UNINDENT .sp and then: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C $ chef\-client .ft P .fi .UNINDENT .UNINDENT .INDENT 0.0 .IP \(bu 2 Use the sudo utility .INDENT 2.0 .INDENT 3.5 .sp .nf .ft C $ sudo chef\-client .ft P .fi .UNINDENT .UNINDENT .IP \(bu 2 Give a user access to read \fB/etc/chef\fP and also the files accessed by the chef\-client. This requires super user privileges and, as such, is not a recommended approach .UNINDENT .SS Windows .sp On Microsoft Windows, running without elevated privileges (when they are necessary) is an issue that fails silently. It will appear that the chef\-client completed its run successfully, but the changes will not have been made. When this occurs, do one of the following to run the chef\-client as the administrator: .INDENT 0.0 .IP \(bu 2 Log in to the administrator account. (This is not the same as an account in the administrator\(aqs security group.) .IP \(bu 2 Run the chef\-client process from the administrator account while being logged into another account. Run the following command: .INDENT 2.0 .INDENT 3.5 .sp .nf .ft C $ runas /user:Administrator "cmd /C chef\-client" .ft P .fi .sp This will prompt for the administrator account password. .UNINDENT .UNINDENT .IP \(bu 2 Open a command prompt by right\-clicking on the command prompt application, and then selecting \fBRun as administrator\fP. After the command window opens, the chef\-client can be run as the administrator .UNINDENT .SH EXAMPLES .sp \fBStart a Chef run when the chef\-client is running as a daemon\fP .sp A chef\-client that is running as a daemon can be woken up and started by sending the process a \fBSIGUSR1\fP. For example, to trigger a chef\-client run on a machine running Linux: .sp .nf .ft C $ sudo killall \-USR1 chef\-client .ft P .fi .sp \fBStart a Chef run manually\fP .sp .nf .ft C $ ps auxw|grep chef\-client .ft P .fi .sp to return something like: .sp .nf .ft C root 66066 0.9 0.0 2488880 264 s001 S+ 10:26AM 0:03.05 /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby /usr/bin/chef\-client \-i 3600 \-s 20 .ft P .fi .sp and then enter: .sp .nf .ft C $ sudo kill \-USR1 66066 .ft P .fi .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/0000755000004100000410000000000012254362222016743 5ustar www-datawww-datachef-11.8.2/distro/common/man/man1/knife-cookbook.10000644000004100000410000004230212254362222021726 0ustar www-datawww-data.TH "KNIFE-COOKBOOK" "1" "Chef 11.8.0" "" "knife cookbook" .SH NAME knife-cookbook \- The man page for the knife cookbook subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp A cookbook is the fundamental unit of configuration and policy distribution. Each cookbook defines a scenario, such as everything needed to install and configure MySQL, and then it contains all of the components that are required to support that scenario, including: .INDENT 0.0 .IP \(bu 2 Attribute values that are set on nodes .IP \(bu 2 Definitions that allow the creation of reusable collections of resources .IP \(bu 2 File distributions .IP \(bu 2 Libraries that extend the chef\-client and/or provide helpers to Ruby code .IP \(bu 2 Recipes that specify which resources to manage and the order in which those resources will be applied .IP \(bu 2 Custom resources and providers .IP \(bu 2 Templates .IP \(bu 2 Versions .IP \(bu 2 Metadata about recipes (including dependencies), version constraints, supported platforms, and so on .UNINDENT .sp The \fBknife cookbook\fP subcommand is used to interact with cookbooks that are located on the server or the local chef\-repo. .sp This subcommand has the following syntax: .sp .nf .ft C $ knife cookbook [ARGUMENT] (options) .ft P .fi .SH COMMON OPTIONS .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .SH BULK DELETE .sp The \fBbulk delete\fP argument is used to delete cookbook files that match a pattern defined by a regular expression. The regular expression must be within quotes and not be surrounded by forward slashes (/). .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife cookbook bulk delete REGEX (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-p\fP, \fB\-\-purge\fP Indicates that a cookbook (or cookbook version) will be removed entirely from the server. This action should be used carefully because only one copy of any single file is stored on the server. Consequently, purging a cookbook will disable any other cookbook that references one or more files from a cookbook that has been purged. .UNINDENT .sp \fBExamples\fP .sp To bulk delete many cookbooks, use a regular expression to define the pattern: .sp .nf .ft C $ knife cookbook bulk delete "^[0\-9]{3}$" \-p .ft P .fi .SH CREATE .sp The \fBcreate\fP argument is used to create a new cookbook directory on the local machine, including the following directories and files: .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .IP \(bu 2 cookbook/attributes .IP \(bu 2 cookbook/CHANGELOG.md .IP \(bu 2 cookbook/definitions .IP \(bu 2 cookbook/files/default .IP \(bu 2 cookbook/libraries .IP \(bu 2 cookbook/metadata.rb .IP \(bu 2 cookbook/providers .IP \(bu 2 cookbook/README.md (or .rdoc) .IP \(bu 2 cookbook/recipes/default.rb .IP \(bu 2 cookbook/resources .IP \(bu 2 cookbook/templates/default .UNINDENT .UNINDENT .UNINDENT .sp After the cookbook is created, it can be uploaded to the server using the \fBknife upload\fP argument. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife cookbook create COOKBOOK_NAME (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-C COPYRIGHT_HOLDER\fP, \fB\-\-copyright COPYRIGHT_HOLDER\fP The name of the copyright holder. This option will place a copyright notice that contains the name of the copyright holder in each of the pre\-created files. If this option is not specified, a copyright name of "your_company_name" will be used instead; it can be easily modified later. .TP .B \fB\-I LICENSE\fP, \fB\-\-license LICENSE\fP The type of license under which a cookbook is distributed: \fBapachev2\fP, \fBgplv2\fP, \fBgplv3\fP, \fBmit\fP, or \fBnone\fP (default). This option will place the appropriate license notice in the pre\-created files. Be aware of the licenses for files inside of a cookbook and be sure to follow any restrictions they describe. .TP .B \fB\-m EMAIL\fP, \fB\-\-email EMAIL\fP The email address for the individual who maintains the cookbook. This option will place an email address in each of the pre\-created files. If this option is not specified, an email name of "your_email" will be used instead; it can be easily modified later. .TP .B \fB\-o PATH\fP, \fB\-\-cookbook\-path PATH\fP The directory in which cookbook are created. This can be a colon\-separated path. .TP .B \fB\-r FORMAT\fP, \fB\-\-readme\-format FORMAT\fP The document format of the readme file: \fBmd\fP (markdown) and \fBrdoc\fP (Ruby docs). .UNINDENT .sp \fBExamples\fP .sp To create a cookbook named "my_cookbook" with copyright, email, license, and readme format options specified, enter: .sp .nf .ft C $ knife cookbook create my_cookbook \-C "My Name" \-m "my@email.com" \-I apachev2 \-r md .ft P .fi .sp to return something like: .sp .nf .ft C ** Creating cookbook my_cookbook ** Creating README for cookbook: my_cookbook ** Creating metadata for cookbook: my_cookbook .ft P .fi .SH DELETE .sp The \fBdelete\fP argument is used to delete a specified cookbook or cookbook version on the server (and not locally). .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife cookbook delete COOKBOOK_NAME [COOKBOOK_VERSION] (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-a\fP, \fB\-\-all\fP Indicates that a cookbook and every version of that cookbook will be deleted. .TP .B \fBCOOKBOOK_VERSION\fP The version of a cookbook to be deleted. If a cookbook has only one version, this option does not need to be specified. If a cookbook has more than one version and this option is not specified, Knife will prompt for a version. .TP .B \fB\-p\fP, \fB\-\-purge\fP Indicates that a cookbook (or cookbook version) will be removed entirely from the server. This action should be used carefully because only one copy of any single file is stored on the server. Consequently, purging a cookbook will disable any other cookbook that references one or more files from a cookbook that has been purged. .UNINDENT .sp \fBExamples\fP .sp To delete version "0.8" from a cookbook named "smartmon", enter: .sp .nf .ft C $ knife cookbook delete smartmon 0.8 .ft P .fi .sp Type \fBY\fP to confirm a deletion. .SH DOWNLOAD .sp The \fBdownload\fP argument is used to download a cookbook from the server to the current working directory. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife cookbook download COOKBOOK_NAME [COOKBOOK_VERSION] (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-d DOWNLOAD_DIRECTORY\fP, \fB\-\-dir DOWNLOAD_DIRECTORY\fP The directory into which a cookbook will be downloaded. .TP .B \fB\-f\fP, \fB\-\-force\fP Indicates that an existing directory will be overwritten. .TP .B \fB\-N\fP, \fB\-\-latest\fP Indicates that the most recent version of a cookbook will be downloaded. .UNINDENT .sp \fBExamples\fP .sp To download a cookbook named "smartmon", enter: .sp .nf .ft C $ knife cookbook download smartmon .ft P .fi .SH LIST .sp The \fBlist\fP argument is used to view a list of cookbooks that are currently available on the server. The list will contain only the most recent version for each cookbook by default. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife cookbook list (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-a\fP, \fB\-\-all\fP Indicates that all available versions of each cookbook will be returned. .TP .B \fB\-w\fP, \fB\-\-with\-uri\fP Indicates that the corresponding URIs will be shown. .UNINDENT .sp \fBExamples\fP .sp To view a list of cookbooks: .sp .nf .ft C $ knife cookbook list .ft P .fi .SH METADATA .sp The \fBmetadata\fP argument is used to generate the metadata for one or more cookbooks. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife cookbook metadata (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-a\fP, \fB\-\-all\fP Indicates that metadata should be generated for all cookbooks, and not just for a specified cookbook. .TP .B \fB\-o PATH:PATH\fP, \fB\-\-cookbook\-path PATH:PATH\fP The directory in which cookbook are created. This can be a colon\-separated path. .UNINDENT .sp \fBExamples\fP .sp To generate metadata for all cookbooks: .sp .nf .ft C $ knife cookbook metadata \-a .ft P .fi .SH METADATA FROM FILE .sp The \fBmetadata from file\fP argument is used to load the metadata for a cookbook from a file. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife cookbook metadata from file FILE .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To view cookbook metadata from a JSON file: .sp .nf .ft C $ knife cookbook metadta from file /path/to/file .ft P .fi .SH SHOW .sp The \fBshow\fP argument is used to view information about a cookbook, parts of a cookbook (attributes, definitions, files, libraries, providers, recipes, resources, and templates), or a file that is associated with a cookbook (including attributes such as checksum or specificity). .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife cookbook show COOKBOOK_NAME [COOKBOOK_VERSION] [PART...] [FILE_NAME] (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fBCOOKBOOK_VERSION\fP The version of a cookbook to be shown. If a cookbook has only one version, this option does not need to be specified. If a cookbook has more than one version and this option is not specified, a list of cookbook versions will be returned. .TP .B \fB\-f FQDN\fP, \fB\-\-fqdn FQDN\fP The FQDN of the host. .TP .B \fBFILE_NAME\fP The name of a file that is associated with a cookbook. .TP .B \fB\-p PLATFORM\fP, \fB\-\-platform PLATFORM\fP The platform for which a cookbook is designed. .TP .B \fBPART\fP The part of the cookbook to show: \fBattributes\fP, \fBdefinitions\fP, \fBfiles\fP, \fBlibraries\fP, \fBproviders\fP, \fBrecipes\fP, \fBresources\fP, or \fBtemplates\fP. More than one part can be specified. .TP .B \fB\-V PLATFORM_VERSION\fP, \fB\-\-platform\-version PLATFORM_VERSION\fP The version of the platform. .TP .B \fB\-w\fP, \fB\-\-with\-uri\fP Indicates that the corresponding URIs will be shown. .UNINDENT .sp \fBExamples\fP .sp To get the list of available versions of a cookbook named "getting\-started", enter: .sp .nf .ft C $ knife cookbook show getting\-started .ft P .fi .sp to return something like: .sp .nf .ft C getting\-started 0.3.0 0.2.0 .ft P .fi .sp To show a list of data about a cookbook using the name of the cookbook and the version, enter: .sp .nf .ft C $ knife cookbook show getting\-started 0.3.0 .ft P .fi .sp to return something like: .sp .nf .ft C attributes: checksum: fa0fc4abf3f6787aeb5c3c5c35de667c name: default.rb path: attributes/default.rb specificity: default url: https://somelongurlhere.com chef_type: cookbook_version cookbook_name: getting\-started definitions: [] files: [] frozen?: false json_class: Chef::CookbookVersion libraries: [] .ft P .fi .sp To only view data about "templates", enter: .sp .nf .ft C $ knife cookbook show getting\-started 0.3.0 templates .ft P .fi .sp to return something like: .sp .nf .ft C checksum: a29d6f254577b830091f140c3a78b1fe name: chef\-getting\-started.txt.erb path: templates/default/chef\-getting\-started.txt.erb specificity: default url: https://someurlhere.com .ft P .fi .sp To view information in JSON format, use the \fB\-F\fP common option as part of the command like this: .sp .nf .ft C $ knife role show devops \-F json .ft P .fi .sp Other formats available include \fBtext\fP, \fByaml\fP, and \fBpp\fP. .SH TEST .sp The \fBtest\fP argument is used to test a cookbook for syntax errors. This argument uses Ruby syntax checking to verify every file in a cookbook that ends in .rb and Embedded Ruby (ERB). .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife cookbook test COOKBOOK_NAME (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-a\fP, \fB\-\-all\fP Indicates that all cookbooks will be tested. .TP .B \fB\-o PATH:PATH\fP, \fB\-\-cookbook\-path PATH:PATH\fP The directory in which cookbook are created. This can be a colon\-separated path. .UNINDENT .sp \fBExamples\fP .sp To test a cookbook named "getting\-started", enter: .sp .nf .ft C $ knife cookbook test getting\-started .ft P .fi .SH UPLOAD .sp The \fBupload\fP argument is used to upload one or more cookbooks (and any files that are associated with those cookbooks) from a local repository to the server. Only files that do not already exist on the server will be uploaded. .IP Note Use a chefignore file to prevent the upload of specific files and file types, such as temporary files or files placed in folders by version control systems. The chefignore file must be located in the root of the cookbook repository and must use rules similar to filename globbing (as defined by the Ruby \fBFile.fnmatch\fP syntax). .RE .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife cookbook upload [COOKBOOK_NAME...] (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-a\fP, \fB\-\-all\fP Indicates that all cookbooks will be uploaded. .TP .B \fB\-d\fP, \fB\-\-include\-dependencies\fP Indicates that when a cookbook has a dependency on one (or more) cookbooks, those cookbooks will also be uploaded. .TP .B \fB\-\-force\fP Indicates that a cookbook should be updated even if the \fB\-\-freeze\fP flag has been set. .TP .B \fB\-\-freeze\fP Indicates that a cookbook cannot be modified; any changes to this cookbook must be included as a new version. Only the \fB\-\-force\fP option can override this setting. .TP .B \fB\-o PATH:PATH\fP, \fB\-\-cookbook\-path PATH:PATH\fP The directory in which cookbook are created. This can be a colon\-separated path. .UNINDENT .sp \fBExamples\fP .sp To upload a cookbook named "getting\-started": .sp .nf .ft C $ knife cookbook upload getting\-started .ft P .fi .sp To upload a cookbook, and then prevent other users from being able to make changes to it, enter: .sp .nf .ft C $ knife cookbook upload redis \-\-freeze .ft P .fi .sp to return something like: .sp .nf .ft C Uploading redis... Upload completed .ft P .fi .sp If a cookbook is frozen and the \fB\-\-force\fP option is not specified, Knife will return an error message similar to the following: .sp .nf .ft C Uploading redis... ERROR: Version 0.1.6 of cookbook redis is frozen. Use \-\-force to override. .ft P .fi .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-node.10000644000004100000410000002742012254362222021051 0ustar www-datawww-data.TH "KNIFE-NODE" "1" "Chef 11.8.0" "" "knife node" .SH NAME knife-node \- The man page for the knife node subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp A node is any physical, virtual, or cloud machine that is configured to be maintained by a chef\-client. .sp The \fBknife node\fP subcommand is used to manage the nodes that exist on a server. .sp This subcommand has the following syntax: .sp .nf .ft C $ knife node [ARGUMENT] (options) .ft P .fi .SH COMMON OPTIONS .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .SH BULK DELETE .sp The \fBbulk delete\fP argument is used to delete one or more nodes that match a pattern defined by a regular expression. The regular expression must be within quotes and not be surrounded by forward slashes (/). .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife node bulk delete REGEX .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To bulk delete many nodes, use a regular expression to define the pattern: .sp .nf .ft C $ knife node bulk delete "^[0\-9]{3}$" .ft P .fi .sp Type \fBY\fP to confirm a deletion. .SH CREATE .sp The \fBcreate\fP argument is used to add a node to the server. Node data is stored as JSON on the server. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife node create NODE_NAME .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To add a node, enter: .sp .nf .ft C $ knife node create node1 .ft P .fi .sp In the $EDITOR enter the node data in JSON: .sp .nf .ft C ## sample: { "normal": { }, "name": "foobar", "override": { }, "default": { }, "json_class": "Chef::Node", "automatic": { }, "run_list": [ "recipe[zsh]", "role[webserver]" ], "chef_type": "node" } .ft P .fi .sp When finished, save it. .SH DELETE .sp The \fBdelete\fP argument is used to delete a node from the server. .IP Note Deleting a node will not delete any corresponding API clients. .RE .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife node delete NODE_NAME .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To delete a node called "dev", enter: .sp .nf .ft C $ knife node delete dev .ft P .fi .SH EDIT .sp The \fBedit\fP argument is used to edit the details of a node on a server. Node data is stored as JSON on the server. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife node edit NODE_NAME (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-a\fP, \fB\-\-all\fP Displays a node in the $EDITOR. By default, attributes that are default, override, or automatic are not shown. .UNINDENT .sp \fBExamples\fP .sp To edit the data for a node named "node1", enter: .sp .nf .ft C $ knife node edit node1 \-a .ft P .fi .sp Update the role data in JSON: .sp .nf .ft C ## sample: { "normal": { }, "name": "node1", "override": { }, "default": { }, "json_class": "Chef::Node", "automatic": { }, "run_list": [ "recipe[devops]", "role[webserver]" ], "chef_type": "node" } .ft P .fi .sp When finished, save it. .SH FROM FILE .sp The \fBfrom file\fP argument is used to create a node using existing node data as a template. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife node from file FILE .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To add a node using data contained in a JSON file: .sp .nf .ft C $ knife node from file "path to JSON file" .ft P .fi .SH LIST .sp The \fBlist\fP argument is used to view all of the nodes that exist on a server. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife node list (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-w\fP, \fB\-\-with\-uri\fP Indicates that the corresponding URIs will be shown. .UNINDENT .sp \fBExamples\fP .sp To verify the list of nodes that are registered with the server, enter: .sp .nf .ft C $ knife node list .ft P .fi .sp to return something similar to: .sp .nf .ft C i\-12345678 rs\-123456 .ft P .fi .SH RUN_LIST ADD .sp The \fBrun_list add\fP argument is used to add run list items (roles or recipes) to a node. A recipe must be in one of the following formats: fully qualified, cookbook, or default. Both roles and recipes must be in quotes, for example: \fB\(aqrole[ROLE_NAME]\(aq\fP or \fB\(aqrecipe[COOKBOOK::RECIPE_NAME]\(aq\fP. Use a comma to separate roles and recipes when adding more than one, like this: \fB\(aqrecipe[COOKBOOK::RECIPE_NAME],COOKBOOK::RECIPE_NAME,role[ROLE_NAME]\(aq\fP. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife node run_list add NODE_NAME RUN_LIST_ITEM (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-a ITEM\fP, \fB\-\-after ITEM\fP Use this to add the run list item after the specified run list item. .UNINDENT .sp \fBExamples\fP .sp To add a role to a run list, enter: .sp .nf .ft C $ knife node run_list add node \(aqrole[ROLE_NAME]\(aq .ft P .fi .sp To add roles and recipes to a run list, enter: .sp .nf .ft C $ knife node run_list add node \(aqrecipe[COOKBOOK::RECIPE_NAME],recipe[COOKBOOK::RECIPE_NAME],role[ROLE_NAME]\(aq .ft P .fi .sp To add a recipe to a run list using the fully qualified format, enter: .sp .nf .ft C $ knife node run_list add node \(aqrecipe[COOKBOOK::RECIPE_NAME]\(aq .ft P .fi .sp To add a recipe to a run list using the cookbook format, enter: .sp .nf .ft C $ knife node run_list add node \(aqCOOKBOOK::RECIPE_NAME\(aq .ft P .fi .sp To add the default recipe of a cookbook to a run list, enter: .sp .nf .ft C $ knife node run_list add node \(aqCOOKBOOK\(aq .ft P .fi .SH RUN_LIST REMOVE .sp The \fBrun_list remove\fP argument is used to remove run list items (roles or recipes) from a node. A recipe must be in one of the following formats: fully qualified, cookbook, or default. Both roles and recipes must be in quotes, for example: \fB\(aqrole[ROLE_NAME]\(aq\fP or \fB\(aqrecipe[COOKBOOK::RECIPE_NAME]\(aq\fP. Use a comma to separate roles and recipes when removing more than one, like this: \fB\(aqrecipe[COOKBOOK::RECIPE_NAME],COOKBOOK::RECIPE_NAME,role[ROLE_NAME]\(aq\fP. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife node run_list remove NODE_NAME RUN_LIST_ITEM .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To remove a role from a run list, enter: .sp .nf .ft C $ knife node run_list remove node \(aqrole[ROLE_NAME]\(aq .ft P .fi .sp To remove a recipe from a run list using the fully qualified format, enter: .sp .nf .ft C $ knife node run_list remove node \(aqrecipe[COOKBOOK::RECIPE_NAME]\(aq .ft P .fi .SH SHOW .sp The \fBshow\fP argument is used to display information about a node. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife node show NODE_NAME (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-a ATTR\fP, \fB\-\-attribute ATTR\fP The attribute (or attributes) to show. .TP .B \fB\-l\fP, \fB\-\-long\fP Display long output when searching nodes while using the default summary format. .TP .B \fB\-m\fP, \fB\-\-medium\fP Display more, but not all, of a node\(aqs data when searching using the default summary format. .TP .B \fB\-r\fP, \fB\-\-run\-list\fP Indicates that only the run\-list will be shown. .UNINDENT .sp \fBExamples\fP .sp To view all data for a node named "build", enter: .sp .nf .ft C $ knife node show build .ft P .fi .sp to return: .sp .nf .ft C Node Name: build Environment: _default FQDN: IP: Run List: Roles: Recipes: Platform: .ft P .fi .sp To show basic information about a node, truncated and nicely formatted: .sp .nf .ft C knife node show .ft P .fi .sp To show all information about a node, nicely formatted: .sp .nf .ft C knife node show \-l .ft P .fi .sp To list a single node attribute: .sp .nf .ft C knife node show \-a .ft P .fi .sp where \fB\fP is something like kernel or platform. (This doesn\(aqt work for nested attributes like \fBnode[kernel][machine]\fP because \fBknife node show\fP doesn\(aqt understand nested attributes.) .sp To view the FQDN for a node named "i\-12345678", enter: .sp .nf .ft C $ knife node show i\-12345678 \-a fqdn .ft P .fi .sp to return: .sp .nf .ft C fqdn: ip\-10\-251\-75\-20.ec2.internal .ft P .fi .sp To view the run list for a node named "dev", enter: .sp .nf .ft C $ knife node show dev \-r .ft P .fi .sp To view information in JSON format, use the \fB\-F\fP common option as part of the command like this: .sp .nf .ft C $ knife role show devops \-F json .ft P .fi .sp Other formats available include \fBtext\fP, \fByaml\fP, and \fBpp\fP. .sp To view node information in raw JSON, use the \fB\-l\fP or \fB\-\-long\fP option: .sp .nf .ft C knife node show \-l \-F json .ft P .fi .sp and/or: .sp .nf .ft C knife node show \-l \-\-format=json .ft P .fi .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-deps.10000644000004100000410000001330512254362222021054 0ustar www-datawww-data.TH "KNIFE-DEPS" "1" "Chef 11.8.0" "" "knife deps" .SH NAME knife-deps \- The man page for the knife deps subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp The \fBknife deps\fP subcommand is used to identify dependencies for a node, role, or cookbook. .sp \fBCommon Options\fP .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife deps (options) .ft P .fi .sp \fBOptions\fP .sp This subcommand has the following options: .INDENT 0.0 .TP .B \fB\-\-chef\-repo\-path PATH\fP The path to the chef\-repo. This setting will override the default path to the chef\-repo. Default: same as specified by \fBchef_repo_path\fP in config.rb. .TP .B \fB\-\-concurrency\fP The number of allowed concurrent connections. Default: \fB10\fP. .TP .B \fB\-\-[no\-]recurse\fP Use \fB\-\-recurse\fP to list dependencies recursively. This option can only be used when \fB\-\-tree\fP is set to \fBtrue\fP. Default: \fB\-\-no\-recurse\fP. .TP .B \fB\-\-remote\fP Indicates that dependencies will be determined from objects located on the server instead of the local chef\-repo. Default: \fBfalse\fP. .TP .B \fB\-\-repo\-mode MODE\fP The layout of the local chef\-repo. Possible values: \fBstatic\fP, \fBeverything\fP, or \fBhosted_everything\fP. Use \fBstatic\fP for just roles, environments, cookbooks, and data bags. By default, \fBeverything\fP and \fBhosted_everything\fP are dynamically selected depending on the server type. Default: \fBeverything\fP / \fBhosted_everything\fP. .TP .B \fB\-\-tree\fP Indicates that dependencies are shown in a visual tree structure (including duplicates, if they exist). Default: \fBfalse\fP. .UNINDENT .sp \fBExamples\fP .sp To find the dependencies for a node: .sp .nf .ft C $ knife deps nodes/node_name.json .ft P .fi .sp To find the dependencies for a role: .sp .nf .ft C $ knife deps roles/role_name.json .ft P .fi .sp To find the dependencies for a cookbook: .sp .nf .ft C $ knife deps cookbooks/cookbook_name.json .ft P .fi .sp To find the dependencies for an environment: .sp .nf .ft C $ knife deps environments/environment_name.json .ft P .fi .sp To find the dependencies for a combination of nodes, cookbooks, roles, and/or environments: .sp .nf .ft C $ knife deps cookbooks/git.json cookbooks/github.json roles/base.json environments/desert.json nodes/mynode.json .ft P .fi .sp To use a wildcard to return all the child nodes: .sp .nf .ft C $ knife deps environments/*.json .ft P .fi .sp Use the \fB\-\-tree\fP option to view the results with structure: .sp .nf .ft C $ knife deps roles/webserver.json .ft P .fi .sp to return something like: .sp .nf .ft C roles/webserver.json roles/base.json cookbooks/github cookbooks/git cookbooks/users cookbooks/apache2 .ft P .fi .sp To pass the output of \fBknife deps\fP to \fBknife upload\fP, do something like the following: .sp .nf .ft C $ knife upload \(gaknife deps nodes/*.json .ft P .fi .sp To pass the output of \fBknife deps\fP to \fBknife xargs\fP: .sp .nf .ft C $ knife deps nodes/*.json | xargs knife upload .ft P .fi .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-exec.10000644000004100000410000002017612254362222021051 0ustar www-datawww-data.TH "KNIFE-EXEC" "1" "Chef 11.8.0" "" "knife exec" .SH NAME knife-exec \- The man page for the knife exec subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp The \fBknife exec\fP subcommand uses the Knife configuration file to execute Ruby scripts in the context of a fully configured chef\-client. This subcommand is most often used to run scripts that will only access server one time (or otherwise very infrequently). Use this subcommand any time that an operation does not warrant full usage of the Knife subcommand library. .sp For Ruby scripts that will be run using the \fBexec\fP subcommand, note the following: .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .IP \(bu 2 The Ruby script must be located on the system from which Knife is run (and not be located on any of the systems that Knife will be managing). .IP \(bu 2 Shell commands will be run from a management workstation. For example, something like \fB%x[ls \-lash /opt/only\-on\-a\-node]\fP would give you the directory listing for the "opt/only\-on\-a\-node" directory or a "No such file or directory" error if the file does not already exist locally. .IP \(bu 2 When the chef\-shell DSL is available, the chef\-client DSL will not be (unless the management workstation is also a chef\-client). Without the chef\-client DSL, a bash block cannot be used to run bash commands. .UNINDENT .UNINDENT .UNINDENT .sp \fBCommon Options\fP .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .sp \fBAuthenticated API Requests\fP .sp The \fBknife exec\fP subcommand can be used to make authenticated API requests to the server using the following methods: .TS center; |l|l|. _ T{ Method T} T{ Description T} _ T{ \fBapi.delete\fP T} T{ Use to delete an object from the server. T} _ T{ \fBapi.get\fP T} T{ Use to get the details of an object on the server. T} _ T{ \fBapi.post\fP T} T{ Use to add an object to the server. T} _ T{ \fBapi.put\fP T} T{ Use to update an object on the server. T} _ .TE .sp These methods are used with the \fB\-E\fP option, which executes that string locally on the workstation using chef\-shell. These methods have the following syntax: .sp .nf .ft C $ knife exec \-E \(aqapi.method(/endpoint)\(aq .ft P .fi .sp where: .INDENT 0.0 .IP \(bu 2 \fBapi.method\fP is the corresponding authentication method \-\-\- \fBapi.delete\fP, \fBapi.get\fP, \fBapi.post\fP, or \fBapi.put\fP .IP \(bu 2 \fB/endpoint\fP is an endpoint in the Chef Server API .UNINDENT .sp For example, to get the data for a node named "Example_Node": .sp .nf .ft C $ knife exec \-E \(aqputs api.get("/nodes/Example_Node")\(aq .ft P .fi .sp and to ensure that the output is visible in the console, add the \fBputs\fP in front of the API authorization request: .sp .nf .ft C $ knife exec \-E \(aqputs api.get("/nodes/Example_Node")\(aq .ft P .fi .sp where \fBputs\fP is the shorter version of the \fB$stdout.puts\fP predefined variable in Ruby. .sp The following example shows how to add a client named "IBM305RAMAC" and the \fB/clients\fP endpoint, and then return the private key for that user in the console: .sp .nf .ft C $ client_desc = { "name" => "IBM305RAMAC", "admin" => false } new_client = api.post("/clients", client_desc) puts new_client["private_key"] .ft P .fi .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife exec SCRIPT (options) .ft P .fi .sp \fBOptions\fP .sp This subcommand has the following options: .INDENT 0.0 .TP .B \fB\-E CODE\fP, \fB\-\-exec CODE\fP A string of code that will be executed. .TP .B \fB\-p PATH:PATH\fP, \fB\-\-script\-path PATH:PATH\fP A colon\-separated path at which Ruby scripts are located. .UNINDENT .sp \fBExamples\fP .sp There are three ways to use \fBknife exec\fP to run Ruby script files. For example: .sp .nf .ft C $ knife exec /path/to/script_file .ft P .fi .sp Or: .sp .nf .ft C $ knife exec \-E \(aqRUBY CODE\(aq .ft P .fi .sp Or: .sp .nf .ft C $ knife exec RUBY CODE ^D .ft P .fi .sp To check the status of Knife using a Ruby script named "status.rb" (which looks like): .sp .nf .ft C printf "%\-5s %\-12s %\-8s %s\en", "Check In", "Name", "Ruby", "Recipes" nodes.all do |n| checkin = Time.at(n[\(aqohai_time\(aq]).strftime("%F %R") rubyver = n[\(aqlanguages\(aq][\(aqruby\(aq][\(aqversion\(aq] recipes = n.run_list.expand(_default).recipes.join(", ") printf "%\-20s %\-12s %\-8s %s\en", checkin, n.name, rubyver, recipes end .ft P .fi .sp and is located in a directory named "scripts", enter: .sp .nf .ft C $ knife exec scripts/status.rb .ft P .fi .sp To show the available free memory for all nodes, enter: .sp .nf .ft C $ knife exec \-E \(aqnodes.all {|n| puts "#{n.name} has #{n.memory.total} free memory"}\(aq .ft P .fi .sp To list all of the available search indexes, enter: .sp .nf .ft C $ knife exec \-E \(aqputs api.get("search").keys\(aq .ft P .fi .sp To query a node for multiple attributes using a Ruby script named \fBsearch_attributes.rb\fP (which looks like): .sp .nf .ft C % cat scripts/search_attributes.rb query = ARGV[2] attributes = ARGV[3].split(",") puts "Your query: #{query}" puts "Your attributes: #{attributes.join(" ")}" results = {} search(:node, query) do |n| results[n.name] = {} attributes.each {|a| results[n.name][a] = n[a]} end puts results exit 0 .ft P .fi .sp enter: .sp .nf .ft C % knife exec scripts/search_attributes.rb "hostname:test_system" ipaddress,fqdn .ft P .fi .sp to return something like: .sp .nf .ft C Your query: hostname:test_system Your attributes: ipaddress fqdn {"test_system.example.com"=>{"ipaddress"=>"10.1.1.200", "fqdn"=>"test_system.example.com"}} .ft P .fi .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-index-rebuild.10000644000004100000410000000676012254362222022663 0ustar www-datawww-data.TH "KNIFE-INDEX-REBUILD" "1" "Chef 11.8.0" "" "knife index rebuild" .SH NAME knife-index-rebuild \- The man page for the knife index rebuild subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp The \fBknife index rebuild\fP subcommand is used to rebuild the search indexes for the open source server. This operation is destructive and may take some time. .IP Note This subcommand ONLY works when run against the open source server version 10.x. This subcommand will NOT run against open source server 11, Enterprise Chef (including hosted Enterprise Chef), or Private Chef. .RE .sp \fBCommon Options\fP .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife index rebuild .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-raw.10000644000004100000410000001127612254362222020717 0ustar www-datawww-data.TH "KNIFE-RAW" "1" "Chef 11.8.0" "" "knife raw" .SH NAME knife-raw \- The man page for the knife raw subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp The \fBknife raw\fP subcommand is used to send a REST request to a specified path using the Chef Server API. .sp \fBCommon Options\fP .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife raw REQUEST_PATH (options) .ft P .fi .sp \fBOptions\fP .sp This subcommand has the following options: .INDENT 0.0 .TP .B \fB\-\-chef\-repo\-path PATH\fP The path to the chef\-repo. This setting will override the default path to the chef\-repo. Default: same as specified by \fBchef_repo_path\fP in config.rb. .TP .B \fB\-\-concurrency\fP The number of allowed concurrent connections. Default: \fB10\fP. .TP .B \fB\-i FILE\fP, \fB\-\-input FILE\fP The name of a file to be used with the \fBPUT\fP or a \fBPOST\fP request. .TP .B \fB\-\-[no\-]pretty\fP Use \fB\-\-no\-pretty\fP to disable pretty\-print output for JSON. Default: \fB\-\-pretty\fP. .TP .B \fB\-m METHOD\fP, \fB\-\-method METHOD\fP The request method: \fBDELETE\fP, \fBGET\fP, \fBPOST\fP, or \fBPUT\fP. Default value: \fBGET\fP. .TP .B \fB\-\-repo\-mode MODE\fP The layout of the local chef\-repo. Possible values: \fBstatic\fP, \fBeverything\fP, or \fBhosted_everything\fP. Use \fBstatic\fP for just roles, environments, cookbooks, and data bags. By default, \fBeverything\fP and \fBhosted_everything\fP are dynamically selected depending on the server type. Default: \fBeverything\fP / \fBhosted_everything\fP. .UNINDENT .sp \fBExamples\fP .sp To view information about a client: .sp .nf .ft C knife raw /clients/ .ft P .fi .sp To view information about a node: .sp .nf .ft C knife raw /nodes/ .ft P .fi .sp To delete a data bag, enter a command similar to: .sp .nf .ft C $ knife raw \-m DELETE /data/foo .ft P .fi .sp to return something similar to: .sp .nf .ft C { "name":"foo", "json_class":"Chef::DataBag", "chef_type":"data_bag" } .ft P .fi .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-recipe-list.10000644000004100000410000000715312254362222022345 0ustar www-datawww-data.TH "KNIFE-RECIPE-LIST" "1" "Chef 11.8.0" "" "knife recipe list" .SH NAME knife-recipe-list \- The man page for the knife recipe list subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp The \fBknife recipe list\fP subcommand is used to view all of the recipes that are on a server. A regular expression can be used to limit the results to recipes that match a specific pattern. The regular expression must be within quotes and not be surrounded by forward slashes (/). .sp \fBCommon Options\fP .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife recipe list REGEX .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To view a list of recipes: .sp .nf .ft C $ knife recipe list \(aqcouchdb::*\(aq .ft P .fi .sp to return: .sp .nf .ft C couchdb::main_monitors couchdb::master couchdb::default couchdb::org_cleanu .ft P .fi .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-cookbook-site.10000644000004100000410000003671712254362222022705 0ustar www-datawww-data.TH "KNIFE-COOKBOOK-SITE" "1" "Chef 11.8.0" "" "knife cookbook site" .SH NAME knife-cookbook-site \- The man page for the knife cookbook site subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp The Cookbooks Site API is used to provide access to the cookbooks community hosted at \fI\%https://cookbooks.opscode.com\fP. All of the cookbooks in the community are accessible through a REST API located at \fI\%https://cookbooks.opscode.com/api/v1/\fP by using any of the supported endpoints. In most cases, using Knife and the \fBknife cookbook site\fP sub\-command (and any of its arguments) is the recommended method of interacting with these cookbooks, but in some cases, using the REST API directly may make sense. .sp The \fBknife cookbook site\fP subcommand is used to interact with cookbooks that are located at \fI\%https://cookbooks.opscode.com\fP. A user account is required for any community actions that write data to this site. The following arguments do not require a user account: \fBdownload\fP, \fBsearch\fP, \fBinstall\fP, and \fBlist\fP. .sp This subcommand has the following syntax: .sp .nf .ft C $ knife cookbook site [ARGUMENT] (options) .ft P .fi .SH COMMON OPTIONS .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .SH DOWNLOAD .sp The \fBdownload\fP argument is used to download a cookbook from the community website. A cookbook will be downloaded as a tar.gz archive and placed in the current working directory. If a cookbook (or cookbook version) has been deprecated and the \fB\-\-force\fP option is not used, Knife will alert the user that the cookbook is deprecated and then will provide the name of the most recent non\-deprecated version of that cookbook. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife cookbook site download COOKBOOK_NAME [COOKBOOK_VERSION] (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fBCOOKBOOK_VERSION\fP The version of a cookbook to be downloaded. If a cookbook has only one version, this option does not need to be specified. If a cookbook has more than one version and this option is not specified, Knife will prompt for a version. .TP .B \fB\-f\fP, \fB\-\-force\fP Indicates that an existing directory will be overwritten. .UNINDENT .sp \fBExamples\fP .sp To download the cookbook "getting\-started", enter: .sp .nf .ft C $ knife cookbook site download getting\-started .ft P .fi .sp to return something like: .sp .nf .ft C Downloading getting\-started from the cookbooks site at version 0.3.0 to /Users/sdanna/opscodesupport/getting\-started\-0.3.0.tar.gz Cookbook saved: /Users/sdanna/opscodesupport/getting\-started\-0.3.0.tar.gz .ft P .fi .SH INSTALL .sp The \fBinstall\fP argument is used to install a cookbook that has been downloaded from the community site to a local git repository . This action uses the git version control system in conjunction with the \fI\%https://cookbooks.opscode.com\fP site to install community\-contributed cookbooks to the local chef\-repo. Using this argument does the following: .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .IP 1. 3 A new "pristine copy" branch is created in git for tracking the upstream. .IP 2. 3 All existing versions of a cookbook are removed from the branch. .IP 3. 3 The cookbook is downloaded from \fI\%https://cookbooks.opscode.com\fP in the tar.gz format. .IP 4. 3 The downloaded cookbook is untarred and its contents are committed to git and a tag is created. .IP 5. 3 The "pristine copy" branch is merged into the master branch. .UNINDENT .UNINDENT .UNINDENT .sp This process allows the upstream cookbook in the master branch to be modified while letting git maintain changes as a separate patch. When an updated upstream version becomes available, those changes can be merged while maintaining any local modifications. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife cookbook site install COOKBOOK_NAME [COOKBOOK_VERSION] (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-b\fP, \fB\-\-use\-current\-branch\fP Indicates that the current branch will be used. .TP .B \fB\-B BRANCH\fP, \fB\-\-branch BRANCH\fP The name of the default branch. This will default to the master branch. .TP .B \fBCOOKBOOK_VERSION\fP The version of the cookbook to be installed. If a version is not specified, the most recent version of the cookbook will be installed. .TP .B \fB\-D\fP, \fB\-\-skip\-dependencies\fP Indicates that all cookbooks to which the installed cookbook has a dependency will not be installed. .TP .B \fB\-o PATH:PATH\fP, \fB\-\-cookbook\-path PATH:PATH\fP The directory in which cookbook are created. This can be a colon\-separated path. .UNINDENT .sp \fBExamples\fP .sp To install the cookbook "getting\-started", enter: .sp .nf .ft C $ knife cookbook site install getting\-started .ft P .fi .sp to return something like: .sp .nf .ft C Installing getting\-started to /Users/sdanna/opscodesupport/.chef/../cookbooks Checking out the master branch. Creating pristine copy branch chef\-vendor\-getting\-started Downloading getting\-started from the cookbooks site at version 0.3.0 to /Users/sdanna/opscodesupport/.chef/../cookbooks/getting\-started.tar.gz Cookbook saved: /Users/sdanna/opscodesupport/.chef/../cookbooks/getting\-started.tar.gz Removing pre\-existing version. Uncompressing getting\-started version /Users/sdanna/opscodesupport/.chef/../cookbooks. removing downloaded tarball 1 files updated, committing changes Creating tag cookbook\-site\-imported\-getting\-started\-0.3.0 Checking out the master branch. Updating 4d44b5b..b4c32f2 Fast\-forward cookbooks/getting\-started/README.rdoc | 4 +++ cookbooks/getting\-started/attributes/default.rb | 1 + cookbooks/getting\-started/metadata.json | 29 ++++++++++++++++++++ cookbooks/getting\-started/metadata.rb | 6 ++++ cookbooks/getting\-started/recipes/default.rb | 23 +++++++++++++++ .../templates/default/chef\-getting\-started.txt.erb | 5 +++ 6 files changed, 68 insertions(+), 0 deletions(\-) create mode 100644 cookbooks/getting\-started/README.rdoc create mode 100644 cookbooks/getting\-started/attributes/default.rb create mode 100644 cookbooks/getting\-started/metadata.json create mode 100644 cookbooks/getting\-started/metadata.rb create mode 100644 cookbooks/getting\-started/recipes/default.rb create mode 100644 cookbooks/getting\-started/templates/default/chef\-getting\-started.txt.erb Cookbook getting\-started version 0.3.0 successfully installed .ft P .fi .SH LIST .sp The \fBlist\fP argument is used to view a list of cookbooks that are currently available at \fI\%https://cookbooks.opscode.com\fP. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife cookbook site list .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-w\fP, \fB\-\-with\-uri\fP Indicates that the corresponding URIs will be shown. .UNINDENT .sp \fBExamples\fP .sp To view a list of cookbooks at \fI\%https://cookbooks.opscode.com\fP server, enter: .sp .nf .ft C $ knife cookbook site list .ft P .fi .sp to return: .sp .nf .ft C 1password homesick rabbitmq 7\-zip hostname rabbitmq\-management AmazonEC2Tag hosts rabbitmq_chef R hosts\-awareness rackspaceknife accounts htop radiant ack\-grep hudson rails activemq icinga rails_enterprise ad id3lib redis\-package ad\-likewise iftop redis2 ant iis redmine [...truncated...] .ft P .fi .SH SEARCH .sp The \fBsearch\fP argument is used to search for a cookbook at \fI\%https://cookbooks.opscode.com\fP. A search query is used to return a list of cookbooks at \fI\%https://cookbooks.opscode.com\fP and uses the same syntax as the \fBknife search\fP sub\-command. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife cookbook site search SEARCH_QUERY (options) .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To search for all of the cookbooks that can be used with Apache, enter: .sp .nf .ft C $ knife cookbook site search apache* .ft P .fi .sp to return something like: .sp .nf .ft C apache2: cookbook: http://cookbooks.opscode.com/api/v1/cookbooks/apache2 cookbook_description: Installs and configures apache2 using Debian symlinks with helper definitions cookbook_maintainer: opscode cookbook_name: apache2 instiki: cookbook: http://cookbooks.opscode.com/api/v1/cookbooks/instiki cookbook_description: Installs instiki, a Ruby on Rails wiki server under passenger+Apache2. cookbook_maintainer: jtimberman cookbook_name: instiki kickstart: cookbook: http://cookbooks.opscode.com/api/v1/cookbooks/kickstart cookbook_description: Creates apache2 vhost and serves a kickstart file. cookbook_maintainer: opscode cookbook_name: kickstart [...truncated...] .ft P .fi .SH SHARE .sp The \fBshare\fP argument is used to add a cookbook to \fI\%https://cookbooks.opscode.com\fP. This action will require a user account and a certificate for \fI\%http://community.opscode.com\fP. By default, Knife will use the user name and API key that is identified in the configuration file used during the upload; otherwise these values must be specified on the command line or in an alternate configuration file. If a cookbook already exists on \fI\%https://cookbooks.opscode.com\fP, then only an owner or maintainer of that cookbook can make updates. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife cookbook site share COOKBOOK_NAME CATEGORY (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fBCATEGORY\fP The cookbook category: \fBDatabases\fP, \fBWeb Servers\fP, \fBProcess Management\fP, \fBMonitoring and Trending\fP, \fBProgramming Languages\fP, \fBPackage Management\fP, \fBApplications\fP, \fBNetworking\fP, \fBOperations Systems and Virtualization\fP, \fBUtilities\fP, or \fBOther\fP. .TP .B \fB\-o PATH:PATH\fP, \fB\-\-cookbook\-path PATH:PATH\fP The directory in which cookbook are created. This can be a colon\-separated path. .UNINDENT .sp \fBExamples\fP .sp To share a cookbook named "apache2": .sp .nf .ft C $ knife cookbook site share "apache2" "Web Servers" .ft P .fi .SH SHOW .sp The \fBshow\fP argument is used to view information about a cookbook on \fI\%https://cookbooks.opscode.com\fP. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife cookbook site show COOKBOOK_NAME [COOKBOOK_VERSION] .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fBCOOKBOOK_VERSION\fP The version of a cookbook to be shown. If a cookbook has only one version, this option does not need to be specified. If a cookbook has more than one version and this option is not specified, a list of cookbook versions will be returned. .UNINDENT .sp \fBExamples\fP .sp To show the details for a cookbook named "haproxy": .sp .nf .ft C $ knife cookbook site show haproxy .ft P .fi .sp to return something like: .sp .nf .ft C average_rating: category: Networking created_at: 2009\-10\-25T23:51:07Z description: Installs and configures haproxy external_url: latest_version: http://cookbooks.opscode.com/api/v1/cookbooks/haproxy/versions/1_0_3 maintainer: opscode name: haproxy updated_at: 2011\-06\-30T21:53:25Z versions: http://cookbooks.opscode.com/api/v1/cookbooks/haproxy/versions/1_0_3 http://cookbooks.opscode.com/api/v1/cookbooks/haproxy/versions/1_0_2 http://cookbooks.opscode.com/api/v1/cookbooks/haproxy/versions/1_0_1 http://cookbooks.opscode.com/api/v1/cookbooks/haproxy/versions/1_0_0 http://cookbooks.opscode.com/api/v1/cookbooks/haproxy/versions/0_8_1 http://cookbooks.opscode.com/api/v1/cookbooks/haproxy/versions/0_8_0 http://cookbooks.opscode.com/api/v1/cookbooks/haproxy/versions/0_7_0 .ft P .fi .sp To view information in JSON format, use the \fB\-F\fP common option as part of the command like this: .sp .nf .ft C $ knife role show devops \-F json .ft P .fi .sp Other formats available include \fBtext\fP, \fByaml\fP, and \fBpp\fP. .SH UNSHARE .sp The \fBunshare\fP argument is used to stop the sharing of a cookbook at \fI\%https://cookbooks.opscode.com\fP. Only the maintainer of a cookbook may perform this action. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife cookbook site unshare COOKBOOK_NAME .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To unshare a cookbook named "getting\-started", enter: .sp .nf .ft C $ knife cookbook site unshare getting\-started .ft P .fi .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-role.10000644000004100000410000002041712254362222021064 0ustar www-datawww-data.TH "KNIFE-ROLE" "1" "Chef 11.8.0" "" "knife role" .SH NAME knife-role \- The man page for the knife role subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp A role is a way to define certain patterns and processes that exist across nodes in an organization as belonging to a single job function. Each role consists of zero (or more) attributes and a run list. Each node can have zero (or more) roles assigned to it. When a role is run against a node, the configuration details of that node are compared against the attributes of the role, and then the contents of that role\(aqs run list are applied to the node\(aqs configuration details. When a chef\-client runs, it merges its own attributes and run lists with those contained within each assigned role. .sp The \fBknife role\fP subcommand is used to manage the roles that are associated with one or more nodes on a server. .sp This subcommand has the following syntax: .sp .nf .ft C $ knife role [ARGUMENT] (options) .ft P .fi .IP Note Use the \fBknife node\fP subcommand (and the \fBrun_list add node\fP argument) to add a role to a node on the server. .RE .SH COMMON OPTIONS .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .SH BULK DELETE .sp The \fBbulk delete\fP argument is used to delete one or more roles that match a pattern defined by a regular expression. The regular expression must be within quotes and not be surrounded by forward slashes (/). .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife role bulk delete REGEX .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To bulk delete roles using a regular expression: .sp .nf .ft C $ knife role bulk delete "^[0\-9]{3}$" .ft P .fi .SH CREATE .sp The \fBcreate\fP argument is used to add a role to the server. To add a role to a node, you must use the \fBnode\fP sub\-command and the \fBrun\-list add\fP argument. Role data is saved as JSON on the server. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife role create ROLE_NAME (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-d DESCRIPTION\fP, \fB\-\-description DESCRIPTION\fP The description of the role. This value will populate the description field for the role on the server. .UNINDENT .sp \fBExamples\fP .sp To add a role named "role1", enter: .sp .nf .ft C $ knife role create role1 .ft P .fi .sp In the $EDITOR enter the role data in JSON: .sp .nf .ft C ## sample: { "name": "role1", "default_attributes": { }, "json_class": "Chef::Role", "run_list": [ ], "description": "", "chef_type": "role", "override_attributes": { } } .ft P .fi .sp When finished, save it. .SH DELETE .sp The \fBdelete\fP argument is used to delete a role from the server. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife role delete ROLE_NAME .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To delete a role: .sp .nf .ft C $ knife role delete devops .ft P .fi .sp Type \fBY\fP to confirm a deletion. .SH EDIT .sp The \fBedit\fP argument is used to edit role details on the server. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife role edit ROLE_NAME .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To edit the data for a role named "role1", enter: .sp .nf .ft C $ knife role edit role1 .ft P .fi .sp Update the role data in JSON: .sp .nf .ft C ## sample: { "name": "role1", "default_attributes": { }, "json_class": "Chef::Role", "run_list": [ ], "description": "This is the description for the role1 role.", "chef_type": "role", "override_attributes": { } } .ft P .fi .sp When finished, save it. .SH FROM FILE .sp The \fBfrom file\fP argument is used to create a role using existing JSON data as a template. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife role from file FILE .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To view role details based on the values contained in a JSON file: .sp .nf .ft C $ knife role from file "path to JSON file" .ft P .fi .SH LIST .sp The \fBlist\fP argument is used to view a list of roles that are currently available on the server. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife role list .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-w\fP, \fB\-\-with\-uri\fP Indicates that the corresponding URIs will be shown. .UNINDENT .sp \fBExamples\fP .sp To view a list of roles on the server and display the URI for each role returned, enter: .sp .nf .ft C $ knife role list \-w .ft P .fi .SH SHOW .sp The \fBshow\fP argument is used to view the details of a role. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife role show ROLE_NAME .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-a ATTR\fP, \fB\-\-attribute ATTR\fP The attribute (or attributes) to show. .UNINDENT .sp \fBExamples\fP .sp To view information in JSON format, use the \fB\-F\fP common option as part of the command like this: .sp .nf .ft C $ knife role show devops \-F json .ft P .fi .sp Other formats available include \fBtext\fP, \fByaml\fP, and \fBpp\fP. .sp To view information in JSON format, use the \fB\-F\fP common option as part of the command like this: .sp .nf .ft C $ knife role show devops \-F json .ft P .fi .sp Other formats available include \fBtext\fP, \fByaml\fP, and \fBpp\fP. .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-search.10000644000004100000410000002026112254362222021365 0ustar www-datawww-data.TH "KNIFE-SEARCH" "1" "Chef 11.8.0" "" "knife search" .SH NAME knife-search \- The man page for the knife search subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp Search indexes allow queries to be made for any type of data that is indexed by the server, including data bags (and data bag items), environments, nodes, and roles. A defined query syntax is used to support search patterns like exact, wildcard, range, and fuzzy. A search is a full\-text query that can be done from several locations, including from within a recipe, by using the \fBsearch\fP subcommand in Knife, by using the search functionality in the Management Console, or by using the \fB/search\fP or \fB/search/INDEX\fP endpoints in the Chef Server API. The search engine is based on Apache Solr and is run from the server. .sp The \fBknife search\fP subcommand is used run a search query for information that is indexed on a server. .sp \fBCommon Options\fP .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife search INDEX SEARCH_QUERY .ft P .fi .sp where \fBINDEX\fP is one of \fBclient\fP, \fBenvironment\fP, \fBnode\fP, \fBrole\fP, or the name of a data bag and \fBSEARCH_QUERY\fP is the search query syntax for the query that will be executed. .sp \fBINDEX\fP is implied if omitted, and will default to \fBnode\fP. For example: .sp .nf .ft C $ knife search \(aq*:*\(aq \-i .ft P .fi .sp will return something similar to: .sp .nf .ft C 8 items found centos\-62\-dev opensuse\-1203 ubuntu\-1304\-dev ubuntu\-1304\-orgtest ubuntu\-1204\-ohai\-test ubuntu\-1304\-ifcfg\-test ohai\-test win2k8\-dev .ft P .fi .sp and is the same search as: .sp .nf .ft C $ knife node search \(aq*:*" \-i .ft P .fi .sp If the \fBSEARCH_QUERY\fP does not contain a colon character (\fB:\fP), then the default query pattern is \fBtags:*#{@query}* OR roles:*#{@query}* OR fqdn:*#{@query}* OR addresses:*#{@query}*\fP, which means the following two search queries are effectively the same: .sp .nf .ft C $ knife search ubuntu .ft P .fi .sp or: .sp .nf .ft C $ knife search node "tags:*ubuntu* OR roles:*ubuntu* OR fqdn:*ubuntu* (etc.)" .ft P .fi .sp \fBOptions\fP .sp This sub\-command has the following options: .INDENT 0.0 .TP .B \fB\-a ATTR\fP, \fB\-\-attribute ATTR\fP The attribute (or attributes) to show. .TP .B \fB\-b ROW\fP, \fB\-\-start ROW\fP The row at which return results will begin. .TP .B \fB\-i\fP, \fB\-\-id\-only\fP Indicates that only matching object IDs will be shown. .TP .B \fBINDEX\fP The name of the index to be queried: \fBclient\fP, \fBenvironment\fP, \fBnode\fP, \fBrole\fP, or \fBDATA_BAG_NAME\fP. Default index: \fBnode\fP. .TP .B \fB\-l\fP, \fB\-\-long\fP Display long output when searching nodes while using the default summary format. .TP .B \fB\-m\fP, \fB\-\-medium\fP Display more, but not all, of a node\(aqs data when searching using the default summary format. .TP .B \fB\-o SORT\fP, \fB\-\-sort SORT\fP The order in which search results will be sorted. .TP .B \fB\-q SEARCH_QUERY\fP, \fB\-\-query SEARCH_QUERY\fP Use to protect search queries that start with a hyphen (\-). A \fB\-q\fP query may be specified as an argument or an option, but not both. .TP .B \fB\-r\fP, \fB\-\-run\-list\fP Indicates that only the run\-list will be shown. .TP .B \fB\-R INT\fP, \fB\-\-rows INT\fP The number of rows to be returned. .TP .B \fBSEARCH_QUERY\fP The search query used to identify a a list of items on a server. This option uses the same syntax as the \fBsearch\fP sub\-command. .UNINDENT .sp \fBExamples\fP .sp To search for the IDs of all nodes running on the Amazon EC2 platform, enter: .sp .nf .ft C $ knife search node \(aqec2:*\(aq \-i .ft P .fi .sp to return something like: .sp .nf .ft C 4 items found ip\-0A7CA19F.ec2.internal ip\-0A58CF8E.ec2.internal ip\-0A58E134.ec2.internal ip\-0A7CFFD5.ec2.internal .ft P .fi .sp To search for the instance type (flavor) of all nodes running on the Amazon EC2 platform, enter: .sp .nf .ft C $ knife search node \(aqec2:*\(aq \-a ec2.instance_type .ft P .fi .sp to return something like: .sp .nf .ft C 4 items found ec2.instance_type: m1.large id: ip\-0A7CA19F.ec2.internal ec2.instance_type: m1.large id: ip\-0A58CF8E.ec2.internal ec2.instance_type: m1.large id: ip\-0A58E134.ec2.internal ec2.instance_type: m1.large id: ip\-0A7CFFD5.ec2.internal .ft P .fi .sp To search for all nodes running Ubuntu, enter: .sp .nf .ft C $ knife search node \(aqplatform:ubuntu\(aq .ft P .fi .sp To search for all nodes running CentOS in the production environment, enter: .sp .nf .ft C $ knife search node \(aqchef_environment:production AND platform:centos\(aq .ft P .fi .sp To find a nested attribute, use a pattern similar to the following: .sp .nf .ft C $ knife search node \-a . .ft P .fi .sp To build a search query to use more than one attribute, use an underscore ( _ ) to separate each attribute. For example, the following query will search for all nodes running a specific version of Ruby: .sp .nf .ft C $ knife search node "languages_ruby_version:1.9.3" .ft P .fi .sp To build a search query that can find a nested attribute: .sp .nf .ft C $ knife search node name: \-a kernel.machine .ft P .fi .sp To test a search query that will be used in a \fBknife ssh\fP command: .sp .nf .ft C $ knife search node "role:web AND NOT name:web03" .ft P .fi .sp where the query in the previous example will search all servers that have the \fBweb\fP role, but not on the server named \fBweb03\fP. .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-list.10000644000004100000410000001221012254362222021066 0ustar www-datawww-data.TH "KNIFE-LIST" "1" "Chef 11.8.0" "" "knife list" .SH NAME knife-list \- The man page for the knife list subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp The \fBknife list\fP subcommand is used to view a list of objects on the server. This subcommand works similar to \fBknife cookbook list\fP, \fBknife data bag list\fP, \fBknife environment list\fP, \fBknife node list\fP, and \fBknife role list\fP, but with a single verb (and a single action). .sp \fBCommon Options\fP .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife list [PATTERN...] (options) .ft P .fi .sp \fBOptions\fP .sp This subcommand has the following options: .INDENT 0.0 .TP .B \fB\-1\fP Indicates that only one results column will be shown. .TP .B \fB\-\-chef\-repo\-path PATH\fP The path to the chef\-repo. This setting will override the default path to the chef\-repo. Default: same as specified by \fBchef_repo_path\fP in config.rb. .TP .B \fB\-\-concurrency\fP The number of allowed concurrent connections. Default: \fB10\fP. .TP .B \fB\-d\fP Indicates that a directory\(aqs children will not be shown when a directory matches a pattern. Default value: \fBfalse\fP. .TP .B \fB\-f\fP, \fB\-\-flat\fP Indicates that a list of file names will be shown. Set to \fBfalse\fP to view ls\-like output. Default: \fBfalse\fP. .TP .B \fB\-\-local\fP Indicates that only contents of the local directory will be returned. Default: \fBfalse\fP. .TP .B \fB\-1\fP Indicates that only one column of results will be shown. Default: \fBfalse\fP. .TP .B \fB\-p\fP Indicates that trailing slashes (/) will be shown for directories. Default: \fBfalse\fP. .TP .B \fB\-R\fP Indicates that directories will be listed recursively. Default: \fBfalse\fP. .TP .B \fB\-\-repo\-mode MODE\fP The layout of the local chef\-repo. Possible values: \fBstatic\fP, \fBeverything\fP, or \fBhosted_everything\fP. Use \fBstatic\fP for just roles, environments, cookbooks, and data bags. By default, \fBeverything\fP and \fBhosted_everything\fP are dynamically selected depending on the server type. Default: \fBeverything\fP / \fBhosted_everything\fP. .UNINDENT .sp \fBExamples\fP .sp For example, to view a list of roles on the server: .sp .nf .ft C $ knife list roles/ .ft P .fi .sp To view a list of roles and environments on the server: .sp .nf .ft C $ knife list roles/ environments/ .ft P .fi .sp To view a list of absolutely everything on the server: .sp .nf .ft C $ knife list \-R / .ft P .fi .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/chef-shell.10000644000004100000410000000740512254362222021045 0ustar www-datawww-data.TH "CHEF-SHELL" "1" "Chef 11.8.0" "" "chef-shell" .SH NAME chef-shell \- The man page for the chef-shell command line tool. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp chef\-shell is a recipe debugging tool that allows the use of breakpoints within recipes. chef\-shell runs as an Interactive Ruby (IRb) session. chef\-shell supports both recipe and attribute file syntax, as well as interactive debugging features. .IP Note chef\-shell is the new name for Shef as of Chef 11.x. chef\-shell is backwards compatible and aside from the name change, has the same set of functionality as with previous releases. .RE .sp The chef\-shell executable can be run as a command\-line tool. .SH MODES .sp chef\-shell is tool that allows Knife to be run using an Interactive Ruby (IRb) session. chef\-shell currently supports recipe and attribute file syntax, as well as interactive debugging features. chef\-shell has three run modes: .TS center; |l|l|. _ T{ Mode T} T{ Description T} _ T{ Standalone T} T{ No cookbooks are loaded, and the run list is empty. This mode is the default. T} _ T{ Solo T} T{ chef\-shell acts as a chef\-solo client. It attempts to load the chef\-solo configuration file and JSON attributes. If the JSON attributes set a run list, it will be honored. Cookbooks will be loaded in the same way that chef\-solo loads them. chef\-solo mode is activated with the \fB\-s\fP or \fB\-\-solo\fP command line option, and JSON attributes are specified in the same way as for chef\-solo, with \fB\-j /path/to/chef\-solo.json\fP. T} _ T{ Client T} T{ chef\-shell acts as a chef\-client. During startup, it reads the chef\-client configuration file and contacts the server to get attributes and cookbooks. The run list will be set in the same way as normal chef\-client runs. chef\-client mode is activated with the \fB\-z\fP or \fB\-\-client\fP options. You can also specify the configuration file with \fB\-c CONFIG\fP and the server URL with \fB\-S SERVER_URL\fP. T} _ .TE .SH OPTIONS .sp This command has the following syntax: .sp .nf .ft C chef\-shell OPTION VALUE OPTION VALUE ... .ft P .fi .sp This command has the following options: .INDENT 0.0 .TP .B \fB\-a\fP, \fB\-\-standalone\fP Indicates that chef\-shell will be run in standalone mode. .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-j PATH\fP, \fB\-\-json\-attributes PATH\fP The path to a file that contains JSON data. Use this option to override attributes that are set from other locations, such as from within a cookbook or by a role. .TP .B \fB\-l LEVEL\fP, \fB\-\-log_level LEVEL\fP The level of logging that will be stored in a log file: \fBdebug\fP, \fBinfo\fP, \fBwarn\fP, \fBerror\fP, or \fBfatal\fP. .TP .B \fB\-s\fP, \fB\-\-solo\fP Indicates that chef\-shell will be run in chef\-solo mode. .TP .B \fB\-S CHEF_SERVER_URL\fP, \fB\-\-server CHEF_SERVER_URL\fP The URL for the server. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-z\fP, \fB\-\-client\fP Indicates that chef\-shell will be run in chef\-client mode. .UNINDENT .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-delete.10000644000004100000410000001072312254362222021364 0ustar www-datawww-data.TH "KNIFE-DELETE" "1" "Chef 11.8.0" "" "knife delete" .SH NAME knife-delete \- The man page for the knife delete subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp The \fBknife delete\fP subcommand is used to delete an object from a server. This subcommand works similar to \fBknife cookbook delete\fP, \fBknife data bag delete\fP, \fBknife environment delete\fP, \fBknife node delete\fP, and \fBknife role delete\fP, but with a single verb (and a single action). .sp \fBCommon Options\fP .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife delete [PATTERN...] (options) .ft P .fi .sp \fBOptions\fP .sp This subcommand has the following options: .INDENT 0.0 .TP .B \fB\-\-both\fP Indicates that both local and remote copies of an object should be deleted. Default: \fBfalse\fP. .TP .B \fB\-\-chef\-repo\-path PATH\fP The path to the chef\-repo. This setting will override the default path to the chef\-repo. Default: same as specified by \fBchef_repo_path\fP in config.rb. .TP .B \fB\-\-concurrency\fP The number of allowed concurrent connections. Default: \fB10\fP. .TP .B \fB\-\-local\fP Indicates that only the local copy of an object should be deleted. (The remote copy will not be deleted.) Default: \fBfalse\fP. .TP .B \fB\-r\fP, \fB\-\-[no\-]recurse\fP Use \fB\-\-recurse\fP to delete directories recursively. Default: \fB\-\-no\-recurse\fP. .TP .B \fB\-\-repo\-mode MODE\fP The layout of the local chef\-repo. Possible values: \fBstatic\fP, \fBeverything\fP, or \fBhosted_everything\fP. Use \fBstatic\fP for just roles, environments, cookbooks, and data bags. By default, \fBeverything\fP and \fBhosted_everything\fP are dynamically selected depending on the server type. Default: \fBeverything\fP / \fBhosted_everything\fP. .UNINDENT .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-configure.10000644000004100000410000001014712254362222022103 0ustar www-datawww-data.TH "KNIFE-CONFIGURE" "1" "Chef 11.8.0" "" "knife configure" .SH NAME knife-configure \- The man page for the knife configure subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp The \fBknife configure\fP subcommand is used to create the knife.rb and client.rb files so that they can be distributed to workstations and nodes. .sp \fBCommon Options\fP .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife configure (options) .ft P .fi .sp \fBOptions\fP .sp This subcommand has the following options: .INDENT 0.0 .TP .B \fB\-\-admin\-client\-name NAME\fP The name of the client, typically the name of the admin client. .TP .B \fB\-\-admin\-client\-key PATH\fP The path to the private key used by the client, typically a file named \fBadmin.pem\fP. .TP .B \fB\-i\fP, \fB\-\-initial\fP Use to create a API client, typically an administrator client on a freshly\-installed server. .TP .B \fB\-r REPO\fP, \fB\-\-repository REPO\fP The path to the chef\-repo. .TP .B \fB\-\-validation\-client\-name NAME\fP The name of the validation client. .TP .B \fB\-\-validation\-key PATH\fP The path to the validation key used by the client, typically a file named \fBvalidation.pem\fP. .UNINDENT .sp \fBExamples\fP .sp To create a knife.rb file, enter: .sp .nf .ft C $ knife configure .ft P .fi .sp To configure a client.rb, enter: .sp .nf .ft C $ knife configure client \(aq/directory\(aq .ft P .fi .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-diff.10000644000004100000410000001571712254362222021042 0ustar www-datawww-data.TH "KNIFE-DIFF" "1" "Chef 11.8.0" "" "knife diff" .SH NAME knife-diff \- The man page for the knife diff subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp The \fBknife diff\fP subcommand is used to compare the differences between files and directories on the server and in the chef\-repo. For example, to compare files on the server prior to an uploading or downloading files using the \fBknife download\fP and \fBknife upload\fP subcommands, or to ensure that certain files in multiple production environments are the same. This subcommand is similar to the \fBgit diff\fP command that can be used to diff what is in the chef\-repo with what is synced to a git repository. .sp \fBCommon Options\fP .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife diff [PATTERN...] (options) .ft P .fi .sp \fBOptions\fP .sp This subcommand has the following options: .INDENT 0.0 .TP .B \fB\-\-chef\-repo\-path PATH\fP The path to the chef\-repo. This setting will override the default path to the chef\-repo. Default: same as specified by \fBchef_repo_path\fP in config.rb. .TP .B \fB\-\-cookbook\-version VERSION\fP The version of a cookbook to be downloaded. .TP .B \fB\-\-concurrency\fP The number of allowed concurrent connections. Default: \fB10\fP. .TP .B \fB\-\-diff\-filter=[(A|D|M|T)...[*]]\fP Indicates that files will be selected that have been added (\fBA\fP), deleted (\fBD\fP), modified (\fBM\fP), and/or have had their type changed (\fBT\fP). Any combination of filter characters may be used, including no filter characters. Use \fB*\fP to select all paths if a file matches other criteria in the comparison. Default value: \fBnil\fP. .TP .B \fB\-\-name\-only\fP Indicates that only the names of modified files will be shown. .TP .B \fB\-\-name\-status\fP Indicates that only the names of files with a status of \fBAdded\fP, \fBDeleted\fP, \fBModified\fP, or \fBType Changed\fP will be shown. .TP .B \fB\-\-no\-recurse\fP Use \fB\-\-no\-recurse\fP to disable listing a directory recursively. Default: \fB\-\-recurse\fP. .TP .B \fB\-\-repo\-mode MODE\fP The layout of the local chef\-repo. Possible values: \fBstatic\fP, \fBeverything\fP, or \fBhosted_everything\fP. Use \fBstatic\fP for just roles, environments, cookbooks, and data bags. By default, \fBeverything\fP and \fBhosted_everything\fP are dynamically selected depending on the server type. Default: \fBeverything\fP / \fBhosted_everything\fP. .UNINDENT .sp \fBknife.rb File Settings\fP .sp In addition to the default settings in a knife.rb file, there are other subcommand\-specific settings that can be added. When a subcommand is run, Knife will use: .INDENT 0.0 .IP 1. 3 A value passed via the command\-line .IP 2. 3 A value contained in the knife.rb file .IP 3. 3 The default value .UNINDENT .sp A value passed via the command line will override a value in the knife.rb file; a value in a knife.rb file will override a default value. .sp The following \fBknife diff\fP settings can be added to the knife.rb file: .INDENT 0.0 .TP .B \fBknife[:chef_repo_path]\fP Use to add the \fB\-\-chef\-repo\-path\fP option. .TP .B \fBknife[:concurrency]\fP Use to add the \fB\-\-concurrency\fP option. .TP .B \fBknife[:name_only]\fP Use to add the \fB\-\-name\-only\fP option. .TP .B \fBknife[:name_status]\fP Use to add the \fB\-\-name\-status\fP option. .TP .B \fBknife[:recurse]\fP Use to add the \fB\-\-recurse\fP option. .TP .B \fBknife[:repo_mode]\fP Use to add the \fB\-\-repo\-mode\fP option. .UNINDENT .sp \fBExamples\fP .sp To compare the "base.json" role to a "webserver.json" role, enter: .sp .nf .ft C $ knife diff roles/base.json roles/webserver.json .ft P .fi .sp To compare the differences between the local chef\-repo and the files that are on the server, enter: .sp .nf .ft C $ knife diff .ft P .fi .sp To diff a node named \fBnode\-lb\fP and then only return files that have been added, deleted, modified, or changed, enter: .sp .nf .ft C $ knife diff \-\-name\-status node\-lb .ft P .fi .sp to return something like: .sp .nf .ft C node\-lb/recipes/eip.rb node\-lb/recipes/heartbeat\-int.rb node\-lb/templates/default/corpsite.conf.erb node\-lb/files/default/wildcard.node.com.crt node\-lb/files/default/wildcard.node.com.crt\-2009 node\-lb/files/default/wildcard.node.com.key node\-lb/.gitignore node\-lb/Rakefile .ft P .fi .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-bootstrap.10000644000004100000410000001646712254362222022152 0ustar www-datawww-data.TH "KNIFE-BOOTSTRAP" "1" "Chef 11.8.0" "" "knife bootstrap" .SH NAME knife-bootstrap \- The man page for the knife bootstrap subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp A bootstrap is a process that installs the chef\-client on a target system so that it can run as a chef\-client and communicate with a server. .sp The \fBknife bootstrap\fP subcommand is used run a bootstrap operation that installs the chef\-client on the target system. The bootstrap operation must specify the IP address or FQDN of the target system. .IP Note To bootstrap the chef\-client on Microsoft Windows machines, the \fI\%knife-windows\fP plugins is required, which includes the necessary bootstrap scripts that are used to do the actual installation. .RE .sp \fBCommon Options\fP .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife bootstrap FQDN_or_IP_ADDRESS (options) .ft P .fi .sp \fBOptions\fP .sp This subcommand has the following options: .INDENT 0.0 .TP .B \fB\-A\fP, \fB\-\-forward\-agent\fP Indicates that SSH agent forwarding is enabled. .TP .B \fB\-\-bootstrap\-proxy PROXY_URL\fP The proxy server for the node that is the target of a bootstrap operation. .TP .B \fB\-\-bootstrap\-version VERSION\fP The version of the chef\-client to install. .TP .B \fB\-d DISTRO\fP, \fB\-\-distro DISTRO\fP The template file to be used during a bootstrap operation. The following distributions are supported: \fBchef\-full\fP (the default bootstrap), \fBcentos5\-gems\fP, \fBfedora13\-gems\fP, \fBubuntu10.04\-gems\fP, \fBubuntu10.04\-apt\fP, \fBubuntu12.04\-gems\fP, and the name of a custom bootstrap template file. When this option is used, Knife will search for the template file in the following order: the \fBbootstrap/\fP folder in the current working directory, the \fBbootstrap/\fP folder in the chef\-repo, the \fBbootstrap/\fP folder in the \fB~/.chef/\fP directory, or a default bootstrap file. Do not use the \fB\-\-template\-file\fP option when \fB\-\-distro\fP is specified. .TP .B \fB\-G GATEWAY\fP, \fB\-\-ssh\-gateway GATEWAY\fP The SSH tunnel or gateway that is used to run a bootstrap action on a machine that is not accessible from the workstation. .TP .B \fB\-\-hint HINT_NAME[=HINT_FILE]\fP An Ohai hint to be set on the target of the bootstrap. The hint is contained in a file and is formatted as JSON: \fB{"attribute":"value","attribute":"value"...}\fP. \fBHINT_NAME\fP is the name of the hint and \fBHINT_FILE\fP is the name of the hint file located at \fB/etc/chef/ohai/hints/HINT_FILE.json\fP. Use multiple \fB\-\-hint\fP options in the command to specify multiple hints. .TP .B \fB\-i IDENTITY_FILE\fP, \fB\-\-identity\-file IDENTITY_FILE\fP The SSH identity file used for authentication. Key\-based authentication is recommended. .TP .B \fB\-j JSON_ATTRIBS\fP, \fB\-\-json\-attributes JSON_ATTRIBS\fP A JSON string that is added to the first run of a chef\-client. .TP .B \fB\-N NAME\fP, \fB\-\-node\-name NAME\fP The name of the node. .TP .B \fB\-\-[no\-]host\-key\-verify\fP Use \fB\-\-no\-host\-key\-verify\fP to disable host key verification. Default setting: \fB\-\-host\-key\-verify\fP. .TP .B \fB\-p PORT\fP, \fB\-\-ssh\-port PORT\fP The SSH port. .TP .B \fB\-P PASSWORD\fP, \fB\-\-ssh\-password PASSWORD\fP The SSH password. This can be used to pass the password directly on the command line. If this option is not specified (and a password is required) Knife will prompt for the password. .TP .B \fB\-\-prerelease\fP Indicates that pre\-release gems should be installed. .TP .B \fB\-r RUN_LIST\fP, \fB\-\-run\-list RUN_LIST\fP A comma\-separated list of roles and/or recipes to be applied. .TP .B \fB\-\-secret SECRET\fP The encryption key that is used for values contained within a data bag. .TP .B \fB\-\-secret\-file FILE\fP The path to the file that contains the encryption key. .TP .B \fB\-\-sudo\fP Indicates that a bootstrap operation should be executed using sudo. .TP .B \fB\-\-template\-file TEMPLATE\fP The path to a template file that will be used during a bootstrap operation. Do not use the \fB\-\-distro\fP option when \fB\-\-template\-file\fP is specified. .TP .B \fB\-\-use\-sudo\-password\fP Indicates that a bootstrap operation is done using sudo, with the password specified by the \fB\-P\fP (or \fB\-\-ssh\-password\fP) option. .TP .B \fB\-x USERNAME\fP, \fB\-\-ssh\-user USERNAME\fP The SSH user name. .UNINDENT .sp \fBExamples\fP .sp To pass an SSH password as part of the command: .sp .nf .ft C $ knife bootstrap 192.168.1.1 \-x username \-P PASSWORD \-\-sudo .ft P .fi .sp To use a file that contains a private key: .sp .nf .ft C $ knife bootstrap 192.168.1.1 \-x username \-i ~/.ssh/id_rsa \-\-sudo .ft P .fi .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-tag.10000644000004100000410000001070712254362222020677 0ustar www-datawww-data.TH "KNIFE-TAG" "1" "Chef 11.8.0" "" "knife tag" .SH NAME knife-tag \- The man page for the knife tag subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp A tag is a custom description that is applied to a node. A tag, once applied, can be helpful when managing nodes using Knife or when building recipes by providing alternate methods of grouping similar types of information. .sp The \fBknife tag\fP subcommand is used to apply tags to nodes on a server. .sp This subcommand has the following syntax: .sp .nf .ft C $ knife tag [ARGUMENT] .ft P .fi .SH COMMON OPTIONS .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .SH CREATE .sp The \fBcreate\fP argument is used to add one or more tags to a node. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife tag create NODE_NAME [TAG...] .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To create tags named "seattle", "portland", and "vancouver", enter: .sp .nf .ft C $ knife tag create node seattle portland vancouver .ft P .fi .SH DELETE .sp The \fBdelete\fP argument is used to delete one or more tags from a node. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife tag delete NODE_NAME [TAG...] .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To delete tags named "denver" and "phoenix", enter: .sp .nf .ft C $ knife tag delete node denver phoenix .ft P .fi .sp Type \fBY\fP to confirm a deletion. .SH LIST .sp The \fBlist\fP argument is used to list all of the tags that have been applied to a node. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife tag list [NODE_NAME...] .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-download.10000644000004100000410000001553412254362222021736 0ustar www-datawww-data.TH "KNIFE-DOWNLOAD" "1" "Chef 11.8.0" "" "knife download" .SH NAME knife-download \- The man page for the knife download subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp The \fBknife download\fP subcommand is used to download roles, cookbooks, environments, nodes, and data bags from the server to the current working directory.. It can be used to back up data on the server, inspect the state of one or more files, or to extract out\-of\-process changes users may have made to files on the server, such as if a user made a change that bypassed version source control. This subcommand is often used in conjunction with \fBknife diff\fP, which can be used to see exactly what changes will be downloaded, and then \fBknife upload\fP, which does the opposite of \fBknife download\fP. .sp \fBCommon Options\fP .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife download [PATTERN...] (options) .ft P .fi .sp \fBOptions\fP .sp This subcommand has the following options: .INDENT 0.0 .TP .B \fB\-\-chef\-repo\-path PATH\fP The path to the chef\-repo. This setting will override the default path to the chef\-repo. Default: same as specified by \fBchef_repo_path\fP in config.rb. .TP .B \fB\-\-concurrency\fP The number of allowed concurrent connections. Default: \fB10\fP. .TP .B \fB\-\-force\fP Use \fB\-\-force\fP to download files even when the file on the hard drive is identical to the object on the server (role, cookbook, etc.). By default, files are compared to see if they have equivalent content, and local files are only overwritten if they are different. Default: \fB\-\-no\-force\fP. .TP .B \fB\-n\fP, \fB\-\-dry\-run\fP Indicates that no action is taken and that results are only printed out. Default: \fBfalse\fP. .TP .B \fB\-\-[no\-]diff\fP Indicates that only new and modified files will be downloaded. Set to \fBfalse\fP to download all files. Default: \fB\-\-diff\fP. .TP .B \fB\-\-[no\-]recurse\fP Use \fB\-\-no\-recurse\fP to disable downloading a directory recursively. Default: \fB\-\-recurse\fP. .TP .B \fB\-\-purge\fP Use \fB\-\-purge\fP to delete local files and directories that do not exist on the server. By default, if a role, cookbook, etc. does not exist on the server, the local file for said role will be left alone and NOT deleted. Default: \fB\-\-no\-purge\fP. .TP .B \fB\-\-repo\-mode MODE\fP The layout of the local chef\-repo. Possible values: \fBstatic\fP, \fBeverything\fP, or \fBhosted_everything\fP. Use \fBstatic\fP for just roles, environments, cookbooks, and data bags. By default, \fBeverything\fP and \fBhosted_everything\fP are dynamically selected depending on the server type. Default: \fBeverything\fP / \fBhosted_everything\fP. .UNINDENT .sp \fBExamples\fP .sp To download the entire chef\-repo from the server, browse to the top level of the chef\-repo and enter: .sp .nf .ft C $ knife download / .ft P .fi .sp To download the \fBcookbooks/\fP directory from the server, browse to the top level of the chef\-repo and enter: .sp .nf .ft C $ knife download cookbooks .ft P .fi .sp or from anywhere in the chef\-repo, enter: .sp .nf .ft C $ knife download /cookbooks .ft P .fi .sp To download the \fBenvironments/\fP directory from the server, browse to the top level of the chef\-repo and enter: .sp .nf .ft C $ knife download environments .ft P .fi .sp or from anywhere in the chef\-repo, enter: .sp .nf .ft C $ knife download /environments .ft P .fi .sp To download an environment named "production" from the server, browse to the top level of the chef\-repo and enter: .sp .nf .ft C $ knife download environments/production.json .ft P .fi .sp or from the \fBenvironments/\fP directory, enter: .sp .nf .ft C $ knife download production.json .ft P .fi .sp To download the \fBroles/\fP directory from the server, browse to the top level of the chef\-repo and enter: .sp .nf .ft C $ knife download roles .ft P .fi .sp or from anywhere in the chef\-repo, enter: .sp .nf .ft C $ knife download /roles .ft P .fi .sp To download all cookbooks that start with "apache" and belong to the "webserver" role, browse to the top level of the chef\-repo and enter: .sp .nf .ft C $ knife download cookbooks/apache\e* roles/webserver.json .ft P .fi .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-client.10000644000004100000410000002341112254362222021376 0ustar www-datawww-data.TH "KNIFE-CLIENT" "1" "Chef 11.8.0" "" "knife client" .SH NAME knife-client \- The man page for the knife client subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp When a node runs the chef\-client for the first time, it generally does not yet have an API client identity, and so it cannot make authenticated requests to the server. This is where the validation client\-\-\-known as the chef\-validator\-\-\-comes in. When the chef\-client runs, it checks if it has a client key. If the client key does not exist, it then attempts to borrow the identity of the chef\-validator to register itself with the server. In order to register with the server, the private key for the chef\-validator needs to be copied to the host and placed in /etc/chef/validation.pem. .sp Once the chef\-client has registered itself with the server, it no longer uses the validation client for anything. It is recommended that you delete the private key for the chef\-validator from the host after the host has registered or use the \fBdelete_validation\fP recipe that can be found in the \fBchef\-client\fP cookbook (\fI\%https://github.com/opscode-cookbooks/chef-client\fP). .sp The \fBknife client\fP subcommand is used to manage an API client list and their associated RSA public key\-pairs. This allows authentication requests to be made to the server by any entity that uses the Chef Server API, such as the chef\-client and Knife. .sp This subcommand has the following syntax: .sp .nf .ft C $ knife client [ARGUMENT] (options) .ft P .fi .SH COMMON OPTIONS .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .SH BULK DELETE .sp The \fBbulk delete\fP argument is used to delete any API client that matches a pattern defined by a regular expression. The regular expression must be within quotes and not be surrounded by forward slashes (/). .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife client bulk delete REGEX .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .SH CREATE .sp The \fBcreate\fP argument is used to create a new API client. This process will generate an RSA key pair for the named API client. The public key will be stored on the server and the private key will be displayed on \fBSTDOUT\fP or written to a named file. .INDENT 0.0 .IP \(bu 2 For the chef\-client, the private key should be copied to the system as /etc/chef/client.pem. .IP \(bu 2 For Knife, the private key is typically copied to ~/.chef/client_name.pem and referenced in the knife.rb configuration file. .UNINDENT .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife client create CLIENT_NAME (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-a\fP, \fB\-\-admin\fP Indicates that a client will be created as an admin client. This is required when users of the open source server need to access the Chef Server API as an administrator. This option only works when used with the open source server and will have no effect when used with Hosted Chef or Private Chef. .UNINDENT .sp \fBExamples\fP .sp To create a Chef Admin client with the name "exampleorg" and save its private key to a file, enter: .sp .nf .ft C $ knife client create exampleorg \-a \-f "/etc/chef/client.pem" .ft P .fi .sp When running the \fBcreate\fP argument on Hosted Chef or Private Chef, be sure to omit the \fB\-a\fP option: .sp .nf .ft C $ knife client create exampleorg \-f "/etc/chef/client.pem" .ft P .fi .SH DELETE .sp The \fBdelete\fP argument is used to delete a registered API client. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife client delete CLIENT_NAME .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To delete a client with the name "client_foo", enter: .sp .nf .ft C $ knife client delete client_foo .ft P .fi .sp Type \fBY\fP to confirm a deletion. .SH EDIT .sp The \fBedit\fP argument is used to edit the details of a registered API client. When this argument is run, Knife will open $EDITOR to enable editing of the \fBadmin\fP attribute. (None of the other attributes should be changed using this argument.) When finished, Knife will update the server with those changes. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife client edit CLIENT_NAME .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To edit a client with the name "exampleorg", enter: .sp .nf .ft C $ knife client edit exampleorg .ft P .fi .SH LIST .sp The \fBlist\fP argument is used to view a list of registered API client. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife client list (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-w\fP, \fB\-\-with\-uri\fP Indicates that the corresponding URIs will be shown. .UNINDENT .sp \fBExamples\fP .sp To verify the API client list for the server, enter: .sp .nf .ft C $ knife client list .ft P .fi .sp to return something similar to: .sp .nf .ft C exampleorg i\-12345678 rs\-123456 .ft P .fi .sp To verify that an API client can authenticate to the server correctly, try getting a list of clients using \fB\-u\fP and \fB\-k\fP options to specify its name and private key: .sp .nf .ft C $ knife client list \-u ORGNAME \-k .chef/ORGNAME.pem .ft P .fi .SH REREGISTER .sp The \fBreregister\fP argument is used to regenerate an RSA key pair for an API client. The public key will be stored on the server and the private key will be displayed on \fBSTDOUT\fP or written to a named file. .IP Note Running this argument will invalidate the previous RSA key pair, making it unusable during authentication to the server. .RE .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife client reregister CLIENT_NAME (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .UNINDENT .sp \fBExamples\fP .sp To regenerate the RSA key pair for a client named "testclient" and save it to a file named "rsa_key", enter: .sp .nf .ft C $ knife client regenerate testclient \-f rsa_key .ft P .fi .SH SHOW .sp The \fBshow\fP argument is used to show the details of an API client. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife client show CLIENT_NAME (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-a ATTR\fP, \fB\-\-attribute ATTR\fP The attribute (or attributes) to show. .UNINDENT .sp \fBExamples\fP .sp To view a client named "testclient", enter: .sp .nf .ft C $ knife client show testclient .ft P .fi .sp to return something like: .sp .nf .ft C admin: false chef_type: client json_class: Chef::ApiClient name: testclient public_key: .ft P .fi .sp To view information in JSON format, use the \fB\-F\fP common option as part of the command like this: .sp .nf .ft C $ knife role show devops \-F json .ft P .fi .sp Other formats available include \fBtext\fP, \fByaml\fP, and \fBpp\fP. .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-data-bag.10000644000004100000410000002531012254362222021560 0ustar www-datawww-data.TH "KNIFE-DATA-BAG" "1" "Chef 11.8.0" "" "knife data bag" .SH NAME knife-data-bag \- The man page for the knife data bag subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp A data bag is a global variable that is stored as JSON data and is accessible from a server. A data bag is indexed for searching and can be loaded by a recipe or accessed during a search. The contents of a data bag can vary, but they often include sensitive information (such as database passwords). .sp The contents of a data bag can be encrypted using \fI\%shared secret encryption\fP. This allows a data bag to store confidential information (such as a database password) or to be managed in a source control system (without plain\-text data appearing in revision history). .sp The \fBknife data bag\fP subcommand is used to manage arbitrary stores of globally available JSON data. .sp This subcommand has the following syntax: .sp .nf .ft C $ knife data bag [ARGUMENT] (options) .ft P .fi .SH COMMON OPTIONS .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .SH CREATE .sp The \fBcreate\fP argument is used to add a data bag to the server. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife data bag create DATA_BAG_NAME [DATA_BAG_ITEM] (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fBDATA_BAG_ITEM\fP The name of a specific item within a data bag. .TP .B \fB\-\-secret SECRET\fP The encryption key that is used for values contained within a data bag. .TP .B \fB\-\-secret\-file FILE\fP The path to the file that contains the encryption key. .UNINDENT .IP Note For encrypted data bag items, use \fIeither\fP \fB\-\-secret\fP or \fB\-\-secret\-file\fP, not both. .RE .sp \fBExamples\fP .sp To create a data bag named "admins", enter: .sp .nf .ft C $ knife data bag create admins .ft P .fi .sp to return: .sp .nf .ft C Created data_bag[admins] .ft P .fi .SH DELETE .sp The \fBdelete\fP argument is used to delete a data bag or a data bag item from a server. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife data bag delete DATA_BAG_NAME [DATA_BAG_ITEM] (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fBDATA_BAG_ITEM\fP The name of a specific item within a data bag. .UNINDENT .sp \fBExamples\fP .sp To a data bag named "admins", enter: .sp .nf .ft C $ knife data bag delete admins .ft P .fi .sp To delete an item named "charlie", enter: .sp .nf .ft C $ knife data bag delete admins charlie .ft P .fi .sp Type \fBY\fP to confirm a deletion. .SH EDIT .sp The \fBedit\fP argument is used to edit the data contained in a data bag. If encryption is being used, the data bag will be decrypted, the data will be made available in the $EDITOR, and then encrypted again before saving it to the server. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife data bag edit DATA_BAG_NAME [DATA_BAG_ITEM] (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fBDATA_BAG_ITEM\fP The name of a specific item within a data bag. .TP .B \fB\-\-secret SECRET\fP The encryption key that is used for values contained within a data bag. .TP .B \fB\-\-secret\-file FILE\fP The path to the file that contains the encryption key. .UNINDENT .IP Note For encrypted data bag items, use \fIeither\fP \fB\-\-secret\fP or \fB\-\-secret\-file\fP, not both. .RE .sp \fBExamples\fP .sp To edit the contents of a data bag, enter: .sp .nf .ft C $ knife data bag edit admins .ft P .fi .sp To edit an item named "charlie" that is contained in a data bag named "admins", enter: .sp .nf .ft C $ knife data bag edit admins charlie .ft P .fi .sp to open the $EDITOR. Once opened, you can update the data before saving it to the server. For example, by changing: .sp .nf .ft C { "id": "charlie" } .ft P .fi .sp to: .sp .nf .ft C { "id": "charlie", "uid": 1005, "gid":"ops", "shell":"/bin/zsh", "comment":"Crazy Charlie" } .ft P .fi .SH FROM FILE .sp The \fBfrom file\fP argument is used to create a data bag on the server from a file. The path to the data bag file must specify one of the following: .INDENT 0.0 .IP \(bu 2 the name of a data bag .IP \(bu 2 a relative or absolute path to a file .UNINDENT .sp If the name of a data bag is specified, Knife will search for the data bag in \fB./data_bags/bag_name/file\fP. Once opened, the JSON file should be a hash that contains at least an ID key which represents the name of the data bag item. .IP Warning A chef\-client must be version 11.6 (or higher) when using the \fBknife data bag from file\fP argument with the Enterprise Chef or Open Source Chef version 11 servers. .RE .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife data bag from file DATA_BAG_NAME_or_PATH .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-a\fP, \fB\-\-all\fP Indicates that all data bags found at the specified path will be uploaded. .TP .B \fB\-\-secret SECRET\fP The encryption key that is used for values contained within a data bag. .TP .B \fB\-\-secret\-file FILE\fP The path to the file that contains the encryption key. .UNINDENT .IP Note For encrypted data bag items, use \fIeither\fP \fB\-\-secret\fP or \fB\-\-secret\-file\fP, not both. .RE .sp \fBExamples\fP .sp To create a data bag on the server from a file: .sp .nf .ft C $ knife data bag from file "path to JSON file" .ft P .fi .sp To create a data bag named "devops_data" that contains encrypted data, enter: .sp .nf .ft C $ knife data bag from file devops_data \-\-secret\-file "path to decryption file" .ft P .fi .SH LIST .sp The \fBlist\fP argument is used to view a list of data bags that are currently available on the server. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife data bag list .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-w\fP, \fB\-\-with\-uri\fP Indicates that the corresponding URIs will be shown. .UNINDENT .sp \fBExamples\fP .sp For example, to view a list of data bags on the server, enter: .sp .nf .ft C $ knife data bag list .ft P .fi .SH SHOW .sp The \fBshow\fP argument is used to view the contents of a data bag. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife data bag show DATA_BAG_NAME (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fBDATA_BAG_ITEM\fP The name of a specific item within a data bag. .TP .B \fB\-\-secret SECRET\fP The encryption key that is used for values contained within a data bag. .TP .B \fB\-\-secret\-file FILE\fP The path to the file that contains the encryption key. .UNINDENT .IP Note For encrypted data bag items, use \fIeither\fP \fB\-\-secret\fP or \fB\-\-secret\-file\fP, not both. .RE .sp \fBExamples\fP .sp To show the contents of a data bag, enter: .sp .nf .ft C $ knife data bag show admins .ft P .fi .sp to return: .sp .nf .ft C charlie .ft P .fi .sp To show the contents of a specific item within data bag, enter: .sp .nf .ft C $ knife data bag show admins charlie .ft P .fi .sp to return: .sp .nf .ft C comment: Crazy Charlie gid: ops id: charlie shell: /bin/zsh uid: 1005 .ft P .fi .sp To show the contents of a data bag named "passwords" with an item that contains encrypted data named "mysql", enter: .sp .nf .ft C $ knife data bag show passwords mysql .ft P .fi .sp to return: .sp .nf .ft C ## sample: { "id": "mysql", "pass": "trywgFA6R70NO28PNhMpGhEvKBZuxouemnbnAUQsUyo=\en", "user": "e/p+8WJYVHY9fHcEgAAReg==\en" } .ft P .fi .sp To show the decrypted contents of the same data bag, enter: .sp .nf .ft C $ knife data bag show \-\-secret\-file /path/to/decryption/file passwords mysql .ft P .fi .sp to return: .sp .nf .ft C ## sample: { "id": "mysql", "pass": "thesecret123", "user": "fred" } .ft P .fi .sp To view information in JSON format, use the \fB\-F\fP common option as part of the command like this: .sp .nf .ft C $ knife data bag show admins \-F json .ft P .fi .sp Other formats available include \fBtext\fP, \fByaml\fP, and \fBpp\fP. .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-show.10000644000004100000410000000734612254362222021111 0ustar www-datawww-data.TH "KNIFE-SHOW" "1" "Chef 11.8.0" "" "knife show" .SH NAME knife-show \- The man page for the knife show subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp The \fBknife show\fP subcommand is used to view the details of one (or more) objects on the server. This subcommand works similar to \fBknife cookbook show\fP, \fBknife data bag show\fP, \fBknife environment show\fP, \fBknife node show\fP, and \fBknife role show\fP, but with a single verb (and a single action). .sp \fBCommon Options\fP .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife show [PATTERN...] (options) .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To show all cookbooks in the \fBcookbooks/\fP directory: .sp .nf .ft C $ knife show cookbooks/ .ft P .fi .sp or, (if already in the \fBcookbooks/\fP directory in the local chef\-repo): .sp .nf .ft C $ knife show .ft P .fi .sp To show roles and environments: .sp .nf .ft C $ knife show roles/ environments/ .ft P .fi .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-environment.10000644000004100000410000001745012254362222022472 0ustar www-datawww-data.TH "KNIFE-ENVIRONMENT" "1" "Chef 11.8.0" "" "knife environment" .SH NAME knife-environment \- The man page for the knife environment subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp An environment is a way to map an organization\(aqs real\-life workflow to what can be configured and managed when using server. Every organization begins with a single environment called the \fB_default\fP environment, which cannot be modified (or deleted). Additional environments can be created to reflect each organization\(aqs patterns and workflow. For example, creating \fBproduction\fP, \fBstaging\fP, \fBtesting\fP, and \fBdevelopment\fP environments. Generally, an environment is also associated with one (or more) cookbook versions. .sp The \fBknife environment\fP subcommand is used to manage environments within a single organization on the server. .sp This subcommand has the following syntax: .sp .nf .ft C $ knife environment [ARGUMENT] (options) .ft P .fi .SH COMMON OPTIONS .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .SH CREATE .sp The \fBcreate\fP argument is used to add an environment object to the server. When this argument is run, Knife will open $EDITOR to enable editing of the \fBENVIRONMENT\fP description field (unless a description is specified as part of the command). When finished, Knife will add the environment to the server. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife environment create ENVIRONMENT_NAME \-d DESCRIPTION .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-d DESCRIPTION\fP, \fB\-\-description DESCRIPTION\fP The description of the environment. This value will populate the description field for the environment on the server. .UNINDENT .sp \fBExamples\fP .sp To create an environment named "dev" with a description of "The development environment.": .sp .nf .ft C $ knife environment create dev \-d "The development environment." .ft P .fi .SH DELETE .sp The \fBdelete\fP argument is used to delete an environment from a server. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife environment delete ENVIRONMENT_NAME .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To delete an environment named "dev", enter: .sp .nf .ft C $ knife environment delete dev .ft P .fi .sp Type \fBY\fP to confirm a deletion. .SH EDIT .sp The \fBedit\fP argument is used to edit the attributes of an environment. When this argument is run, Knife will open $EDITOR to enable editing of \fBENVIRONMENT\fP attributes. When finished, Knife will update the server with those changes. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife environment edit ENVIRONMENT_NAME .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To edit an environment named "devops", enter: .sp .nf .ft C $ knife environment edit devops .ft P .fi .SH FROM FILE .sp The \fBfrom file\fP argument is used to add or update an environment using a JSON or Ruby DSL description. It must be run with the \fBcreate\fP or \fBedit\fP arguments. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife environment [create | edit] from file FILE (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-a\fP, \fB\-\-all\fP Indicates that all environments found at the specified path will be uploaded. .UNINDENT .sp \fBExamples\fP .sp To add an environment using data contained in a JSON file: .sp .nf .ft C $ knife environment create devops from file "path to JSON file" .ft P .fi .sp or: .sp .nf .ft C $ knife environment edit devops from file "path to JSON file" .ft P .fi .SH LIST .sp The \fBlist\fP argument is used to list all of the environments that are currently available on the server. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife environment list \-w .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-w\fP, \fB\-\-with\-uri\fP Indicates that the corresponding URIs will be shown. .UNINDENT .sp \fBExamples\fP .sp To view a list of environments: .sp .nf .ft C $ knife environment list \-w .ft P .fi .SH SHOW .sp The \fBshow\fP argument is used to display information about the specified environment. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife environment show ENVIRONMENT_NAME .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To view information about the "dev" environment enter: .sp .nf .ft C $ knife environment show dev .ft P .fi .sp to return: .sp .nf .ft C % knife environment show dev chef_type: environment cookbook_versions: default_attributes: description: json_class: Chef::Environment name: dev override_attributes: \e\e \e\e \e\e \e\e .ft P .fi .sp To view information in JSON format, use the \fB\-F\fP common option as part of the command like this: .sp .nf .ft C $ knife role show devops \-F json .ft P .fi .sp Other formats available include \fBtext\fP, \fByaml\fP, and \fBpp\fP. .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-status.10000644000004100000410000001505512254362222021450 0ustar www-datawww-data.TH "KNIFE-STATUS" "1" "Chef 11.8.0" "" "knife status" .SH NAME knife-status \- The man page for the knife status subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp The \fBknife status\fP subcommand is used to display a brief summary of the nodes on a server, including the time of the most recent successful chef\-client run. .sp \fBCommon Options\fP .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife status (options) .ft P .fi .sp \fBOptions\fP .sp This subcommand has the following options: .INDENT 0.0 .TP .B \fBQUERY\fP The search query used to identify a a list of items on a server. This option uses the same syntax as the \fBsearch\fP sub\-command. .TP .B \fB\-H\fP, \fB\-\-hide\-healthy\fP Indicates that nodes on which a chef\-client run has occurred within the previous hour will be hidden. .TP .B \fB\-r RUN_LIST\fP, \fB\-\-run\-list RUN_LIST\fP A comma\-separated list of roles and/or recipes to be applied. .TP .B \fB\-s\fP, \fB\-\-sort\-reverse\fP Indicates that the list will be sorted by last run time, descending. .UNINDENT .sp \fBExamples\fP .sp To include run lists in the status, enter: .sp .nf .ft C $ knife status \-\-run\-list .ft P .fi .sp to return something like: .sp .nf .ft C 20 hours ago, dev\-vm.chisamore.com, ubuntu 10.04, dev\-vm.chisamore.com, 10.66.44.126, role[lb]. 3 hours ago, i\-225f954f, ubuntu 10.04, ec2\-67\-202\-63\-102.compute\-1.amazonaws.com, 67.202.63.102, role[web]. 3 hours ago, i\-a45298c9, ubuntu 10.04, ec2\-174\-129\-127\-206.compute\-1.amazonaws.com, 174.129.127.206, role[web]. 3 hours ago, i\-5272a43f, ubuntu 10.04, ec2\-184\-73\-9\-250.compute\-1.amazonaws.com, 184.73.9.250, role[web]. 3 hours ago, i\-226ca64f, ubuntu 10.04, ec2\-75\-101\-240\-230.compute\-1.amazonaws.com, 75.101.240.230, role[web]. 3 hours ago, i\-f65c969b, ubuntu 10.04, ec2\-184\-73\-60\-141.compute\-1.amazonaws.com, 184.73.60.141, role[web]. .ft P .fi .sp To show the status for nodes on which the chef\-client did not run successfully within the past hour, enter: .sp .nf .ft C $ knife status \-\-hide\-healthy .ft P .fi .sp to return something like: .sp .nf .ft C 1 hour ago, i\-256f884f, ubuntu 12.04, ec2\-67\-202\-63\-102.compute\-1.amazonaws.com, 67.202.63.102, role[web]. 1 hour ago, i\-a47823c9, ubuntu 10.04, ec2\-174\-129\-127\-206.compute\-1.amazonaws.com, 184.129.143.111, role[lb]. .ft P .fi .sp To show the status of a subset of nodes that are returned by a specific query, enter: .sp .nf .ft C $ knife status "role:web" \-\-run\-list .ft P .fi .sp to return something like: .sp .nf .ft C 3 hours ago, i\-225f954f, ubuntu 10.04, ec2\-67\-202\-63\-102.compute\-1.amazonaws.com, 67.202.63.102, role[web]. 3 hours ago, i\-a45298c9, ubuntu 10.04, ec2\-174\-129\-127\-206.compute\-1.amazonaws.com, 174.129.127.206, role[web]. 3 hours ago, i\-5272a43f, ubuntu 10.04, ec2\-184\-73\-9\-250.compute\-1.amazonaws.com, 184.73.9.250, role[web]. 3 hours ago, i\-226ca64f, ubuntu 10.04, ec2\-75\-101\-240\-230.compute\-1.amazonaws.com, 75.101.240.230, role[web]. 3 hours ago, i\-f65c969b, ubuntu 10.04, ec2\-184\-73\-60\-141.compute\-1.amazonaws.com, 184.73.60.141, role[web]. .ft P .fi .sp To view the status of all nodes in the organization, enter: .sp .nf .ft C $ knife status .ft P .fi .sp to return something like: .sp .nf .ft C 20 hours ago, dev\-vm.chisamore.com, ubuntu 10.04, dev\-vm.chisamore.com, 10.66.44.126 3 hours ago, i\-225f954f, ubuntu 10.04, ec2\-67\-202\-63\-102.compute\-1.amazonaws.com, 67.202.63.102 3 hours ago, i\-a45298c9, ubuntu 10.04, ec2\-174\-129\-127\-206.compute\-1.amazonaws.com, 174.129.127.206 3 hours ago, i\-5272a43f, ubuntu 10.04, ec2\-184\-73\-9\-250.compute\-1.amazonaws.com, 184.73.9.250 3 hours ago, i\-226ca64f, ubuntu 10.04, ec2\-75\-101\-240\-230.compute\-1.amazonaws.com, 75.101.240.230 3 hours ago, i\-f65c969b, ubuntu 10.04, ec2\-184\-73\-60\-141.compute\-1.amazonaws.com, 184.73.60.141 .ft P .fi .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-user.10000644000004100000410000001724212254362222021103 0ustar www-datawww-data.TH "KNIFE-USER" "1" "Chef 11.8.0" "" "knife user" .SH NAME knife-user \- The man page for the knife user subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp The \fBknife user\fP subcommand is used to manage the list of users and their associated RSA public key\-pairs. .IP Note This subcommand ONLY works when run against the open source server and will not run against Enterprise Chef (including hosted Enterprise Chef), or Private Chef. .RE .sp This subcommand has the following syntax: .sp .nf .ft C $ knife user [ARGUMENT] (options) .ft P .fi .SH COMMON OPTIONS .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .SH CREATE .sp The \fBcreate\fP argument is used to create a user. This process will generate an RSA key pair for the named user. The public key will be stored on the server and the private key will be displayed on \fBSTDOUT\fP or written to a named file. .INDENT 0.0 .IP \(bu 2 For the user, the private key should be copied to the system as /etc/chef/client.pem. .IP \(bu 2 For Knife, the private key is typically copied to ~/.chef/client_name.pem and referenced in the knife.rb configuration file. .UNINDENT .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife user create USER_NAME (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-a\fP, \fB\-\-admin\fP Indicates that a client will be created as an admin client. This is required when users of the open source server need to access the Chef Server API as an administrator. This option only works when used with the open source server and will have no effect when used with Hosted Chef or Private Chef. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-user\-key FILE_NAME\fP All users are assigned a public key. Use to write the public key to a file. .UNINDENT .sp \fBExamples\fP .sp To create a new user named "Radio Birdman" with a private key saved to "/keys/user_name", enter: .sp .nf .ft C $ knife user create "Radio Birdman" \-f /keys/user_name .ft P .fi .SH DELETE .sp The \fBdelete\fP argument is used to delete a registered user. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife user delete USER_NAME .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp To delete a user named "Steve Danno", enter: .sp .nf .ft C $ knife user delete "Steve Danno" .ft P .fi .SH EDIT .sp The \fBedit\fP argument is used to edit the details of a user. When this argument is run, Knife will open $EDITOR. When finished, Knife will update the server with those changes. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife user edit USER_NAME .ft P .fi .sp \fBOptions\fP .sp This command does not have any specific options. .sp \fBExamples\fP .sp None. .SH LIST .sp The \fBlist\fP argument is used to view a list of registered users. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife user list (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-w\fP, \fB\-\-with\-uri\fP Indicates that the corresponding URIs will be shown. .UNINDENT .sp \fBExamples\fP .sp None. .SH REREGISTER .sp The \fBreregister\fP argument is used to regenerate an RSA key pair for a user. The public key will be stored on the server and the private key will be displayed on \fBSTDOUT\fP or written to a named file. .IP Note Running this argument will invalidate the previous RSA key pair, making it unusable during authentication to the server. .RE .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife user reregister USER_NAME (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .UNINDENT .sp \fBExamples\fP .sp To regenerate the RSA key pair for a user named "Robert Younger", enter: .sp .nf .ft C $ knife user reregister "Robert Younger" .ft P .fi .SH SHOW .sp The \fBshow\fP argument is used to show the details of a user. .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife user show USER_NAME (options) .ft P .fi .sp \fBOptions\fP .sp This argument has the following options: .INDENT 0.0 .TP .B \fB\-a ATTR\fP, \fB\-\-attribute ATTR\fP The attribute (or attributes) to show. .UNINDENT .sp \fBExamples\fP .sp To view a user named "Dennis Teck", enter: .sp .nf .ft C $ knife user show "Dennis Teck" .ft P .fi .sp to return something like: .sp .nf .ft C chef_type: user json_class: Chef::User name: Dennis Teck public_key: .ft P .fi .sp To view information in JSON format, use the \fB\-F\fP common option as part of the command like this: .sp .nf .ft C $ knife user show "Dennis Teck" \-F json .ft P .fi .sp Other formats available include \fBtext\fP, \fByaml\fP, and \fBpp\fP. .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-upload.10000644000004100000410000001563712254362222021417 0ustar www-datawww-data.TH "KNIFE-UPLOAD" "1" "Chef 11.8.0" "" "knife upload" .SH NAME knife-upload \- The man page for the knife upload subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp The \fBknife upload\fP subcommand is used to upload roles, cookbooks, environments, and data bags to the server from the current working directory in the chef\-repo. This subcommand is often used in conjunction with \fBknife diff\fP, which can be used to see exactly what changes will be uploaded, and then \fBknife download\fP, which does the opposite of \fBknife upload\fP. .sp \fBCommon Options\fP .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife upload [PATTERN...] (options) .ft P .fi .sp \fBOptions\fP .sp This subcommand has the following options: .INDENT 0.0 .TP .B \fB\-\-chef\-repo\-path PATH\fP The path to the chef\-repo. This setting will override the default path to the chef\-repo. Default: same as specified by \fBchef_repo_path\fP in config.rb. .TP .B \fB\-\-concurrency\fP The number of allowed concurrent connections. Default: \fB10\fP. .TP .B \fB\-\-[no\-]diff\fP Indicates that only new and modified files will be uploaded. Set to \fBfalse\fP to upload all files. Default: \fBtrue\fP. .TP .B \fB\-\-[no\-]force\fP Use \fB\-\-force\fP to upload roles, cookbooks, etc. even if the file in the directory is identical (by default, no \fBPOST\fP or \fBPUT\fP is performed unless an actual change would be made). Default: \fB\-\-no\-force\fP. .TP .B \fB\-\-[no\-]freeze\fP Indicates that a cookbook cannot be modified; any changes to this cookbook must be included as a new version. Only the \fB\-\-force\fP option can override this setting. Default: \fBfalse\fP. .TP .B \fB\-n\fP, \fB\-\-dry\-run\fP Indicates that no action is taken and that results are only printed out. Default: \fBfalse\fP. .TP .B \fB\-\-[no\-]purge\fP Use \fB\-\-purge\fP to delete roles, cookbooks, etc. from the server if their corresponding files do not exist in the chef\-repo. By default, such objects are left alone and NOT purged. Default: \fB\-\-no\-purge\fP. .TP .B \fB\-\-[no\-]recurse\fP Use \fB\-\-no\-recurse\fP to disable uploading a directory recursively. Default: \fB\-\-recurse\fP. .TP .B \fB\-\-repo\-mode MODE\fP The layout of the local chef\-repo. Possible values: \fBstatic\fP, \fBeverything\fP, or \fBhosted_everything\fP. Use \fBstatic\fP for just roles, environments, cookbooks, and data bags. By default, \fBeverything\fP and \fBhosted_everything\fP are dynamically selected depending on the server type. Default: \fBeverything\fP / \fBhosted_everything\fP. .UNINDENT .sp \fBExamples\fP .sp To upload the entire chef\-repo to the server, browse to the top level of the chef\-repo and enter: .sp .nf .ft C $ knife upload .ft P .fi .sp or from anywhere in the chef\-repo, enter: .sp .nf .ft C $ knife upload / .ft P .fi .sp To upload the \fBcookbooks/\fP directory to the server, browse to the top level of the chef\-repo and enter: .sp .nf .ft C $ knife upload cookbooks .ft P .fi .sp or from anywhere in the chef\-repo, enter: .sp .nf .ft C $ knife upload /cookbooks .ft P .fi .sp To upload the \fBenvironments/\fP directory to the server, browse to the top level of the chef\-repo and enter: .sp .nf .ft C $ knife upload environments .ft P .fi .sp or from anywhere in the chef\-repo, enter: .sp .nf .ft C $ knife upload /environments .ft P .fi .sp To upload an environment named "production" to the server, browse to the top level of the chef\-repo and enter: .sp .nf .ft C $ knife upload environments/production.json .ft P .fi .sp or from the \fBenvironments/\fP directory, enter: .sp .nf .ft C $ knife upload production.json .ft P .fi .sp To upload the \fBroles/\fP directory to the server, browse to the top level of the chef\-repo and enter: .sp .nf .ft C $ knife upload roles .ft P .fi .sp or from anywhere in the chef\-repo, enter: .sp .nf .ft C $ knife upload /roles .ft P .fi .sp To upload all cookbooks that start with "apache" and belong to the "webserver" role, browse to the top level of the chef\-repo and enter: .sp .nf .ft C $ knife upload cookbooks/apache\e* roles/webserver.json .ft P .fi .sp Use the output of \fBknife deps\fP to pass a command to \fBknife upload\fP. For example: .sp .nf .ft C $ knife upload \(gaknife deps nodes/*.json\(ga .ft P .fi .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife.10000644000004100000410000001530212254362222020122 0ustar www-datawww-data.TH "KNIFE" "1" "Chef 11.8.0" "" "knife" .SH NAME knife \- The man page for the knife command line tool. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp Knife is a command\-line tool that provides an interface between a local chef\-repo and the server. Knife helps users to manage: .INDENT 0.0 .IP \(bu 2 Nodes .IP \(bu 2 Cookbooks and recipes .IP \(bu 2 Roles .IP \(bu 2 Stores of JSON data (data bags), including encrypted data .IP \(bu 2 Environments .IP \(bu 2 Cloud resources, including provisioning .IP \(bu 2 The installation of the chef\-client on management workstations .IP \(bu 2 Searching of indexed data on the server .UNINDENT .sp Knife subcommands: .INDENT 0.0 .IP \(bu 2 knife bootstrap .IP \(bu 2 knife client .IP \(bu 2 knife configure .IP \(bu 2 knife cookbook .IP \(bu 2 knife cookbook site .IP \(bu 2 knife data bag .IP \(bu 2 knife delete .IP \(bu 2 knife deps .IP \(bu 2 knife diff .IP \(bu 2 knife download .IP \(bu 2 knife edit .IP \(bu 2 knife environment .IP \(bu 2 knife exec .IP \(bu 2 knife list .IP \(bu 2 knife node .IP \(bu 2 knife raw .IP \(bu 2 knife recipe list .IP \(bu 2 knife role .IP \(bu 2 knife search .IP \(bu 2 knife show .IP \(bu 2 knife ssh .IP \(bu 2 knife status .IP \(bu 2 knife tag .IP \(bu 2 knife upload .IP \(bu 2 knife user .IP \(bu 2 knife xargs .UNINDENT .SH WORKING WITH KNIFE .sp Knife runs from a management workstation and sits in\-between a server and an organization\(aqs infrastructure. Knife interacts with a server by using the same REST API that is used by a chef\-client. Role\-based authentication controls (RBAC) can be used to authorize changes when Knife is run with Hosted Chef or Private Chef. Knife is configured during workstation setup, but subsequent modifications can be made using the knife.rb configuration file. .SS JSON Data Format .sp Most data is entered using a text editor in JSON format, unless the \fB\-\-disable\-editing\fP option is entered as part of a command. (Encrypted data bags use YAML, which is a superset of JSON.) JSON is a common, language\-independent data format that provides a simple text representation of arbitrary data structures. For more information about JSON, see \fI\%http://www.json.org/\fP or \fI\%http://en.wikipedia.org/wiki/JSON\fP. .SS Set the Text Editor .sp Some Knife commands, such as \fBknife data bag edit\fP, require that information be edited as JSON data using a text editor. For example, the following command: .sp .nf .ft C $ knife data bag edit admins admin_name .ft P .fi .sp will open up the text editor with data similar to: .sp .nf .ft C { "id": "admin_name" } .ft P .fi .sp Changes to that file can then be made: .sp .nf .ft C { "id": "Justin C." "description": "I am passing the time by letting time pass over me ..." } .ft P .fi .sp The type of text editor that is used by Knife can be configured by adding an entry to the knife.rb file or by setting an \fBEDITOR\fP environment variable. For example, to configure the text editor to always open with vim, add the following to the knife.rb file: .sp .nf .ft C knife[:editor] = "/usr/bin/vim" .ft P .fi .sp When a Microsoft Windows file path is enclosed in a double\-quoted string (" "), the same backslash character (\fB\e\fP) that is used to define the file path separator is also used in Ruby to define an escape character. The knife.rb file is a Ruby file; therefore, file path separators must be escaped. In addition, spaces in the file path must be replaced with \fB~1\fP so that the length of each section within the file path is not more than 8 characters. For example, if EditPad Pro is the text editor of choice and is located at the following path: .sp .nf .ft C C:\e\eProgram Files (x86)\eEditPad Pro\eEditPad.exe .ft P .fi .sp the setting in the knife.rb file would be similar to: .sp .nf .ft C knife[:editor] = "C:\e\eProgra~1\e\eEditPa~1\e\eEditPad.exe" .ft P .fi .sp One approach to working around the double\- vs. single\-quote issue is to put the single\-quotes outside of the double\-quotes. For example, for Notepad++: .sp .nf .ft C knife[:editor] = \(aq"C:\eProgram Files (x86)\eNotepad++\enotepad++.exe \-nosession \-multiInst"\(aq .ft P .fi .sp for Sublime Text: .sp .nf .ft C knife[:editor] = \(aq"C:\eProgram Files\eSublime Text 2\esublime_text.exe \-\-wait"\(aq .ft P .fi .sp for TextPad: .sp .nf .ft C knife[:editor] = \(aq"C:\eProgram Files (x86)\eTextPad 7\eTextPad.exe"\(aq .ft P .fi .sp and for vim: .sp .nf .ft C knife[:editor] = \(aq"C:\eProgram Files (x86)\evim\evim74\egvim.exe"\(aq .ft P .fi .SS Using Quotes .sp Values can be entered with double quotes (" ") or single quotes (\(aq \(aq), but this should be done consistently. .SS Sub\-commands .sp Knife comes with a collection of built in subcommands that work together to provide all of the functionality required to take specific actions against any object in an organization, including cookbooks, nodes, roles, data bags, environments, and users. A Knife plugin extends the functionality beyond built\-in subcommands. .sp Knife has the following subcommands: \fBbootstrap\fP, \fBclient\fP, \fBconfigure\fP, \fBcookbook\fP, \fBcookbook site\fP, \fBdata bag\fP, \fBdelete\fP, \fBdeps\fP, \fBdiff\fP, \fBdownload\fP, \fBedit\fP, \fBenvironment\fP, \fBexec\fP, \fBindex rebuild\fP, \fBlist\fP, \fBnode\fP, \fBrecipe list\fP, \fBrole\fP, \fBsearch\fP, \fBshow\fP, \fBssh\fP, \fBstatus\fP, \fBtag\fP, \fBupload\fP, \fBuser\fP, and \fBxargs\fP. .IP Note The following subcommands run only against the open source server: \fBindex rebuild\fP and \fBuser\fP. .RE .SS Syntax .sp All Knife subcommands have the following syntax: .INDENT 0.0 .INDENT 3.5 knife subcommand [ARGUMENT] (options) .UNINDENT .UNINDENT .sp Each subcommand has its own set of arguments and options. .IP Note All syntax examples in this document show variables in ALL_CAPS. For example \fB\-u PORT_LIST\fP (where PORT_LIST is a comma\-separated list of local and public UDP ports) or \fB\-F FORMAT\fP (where FORMAT determines the output format, either \fBsummary\fP, \fBtext\fP, \fBjson\fP, \fByaml\fP, or \fBpp\fP). These variables often require specific values that are unique to each organization. .RE .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-edit.10000644000004100000410000001021712254362222021045 0ustar www-datawww-data.TH "KNIFE-EDIT" "1" "Chef 11.8.0" "" "knife edit" .SH NAME knife-edit \- The man page for the knife edit subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp The \fBknife edit\fP subcommand is used to edit objects on the server. This subcommand works similar to \fBknife cookbook edit\fP, \fBknife data bag edit\fP, \fBknife environment edit\fP, \fBknife node edit\fP, and \fBknife role edit\fP, but with a single verb (and a single action). .sp \fBCommon Options\fP .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife edit (options) .ft P .fi .sp \fBOptions\fP .sp This subcommand has the following options: .INDENT 0.0 .TP .B \fB\-\-chef\-repo\-path PATH\fP The path to the chef\-repo. This setting will override the default path to the chef\-repo. Default: same as specified by \fBchef_repo_path\fP in config.rb. .TP .B \fB\-\-concurrency\fP The number of allowed concurrent connections. Default: \fB10\fP. .TP .B \fB\-\-local\fP Use to show files in the local chef\-repo instead of a remote location. Default: \fBfalse\fP. .TP .B \fB\-\-repo\-mode MODE\fP The layout of the local chef\-repo. Possible values: \fBstatic\fP, \fBeverything\fP, or \fBhosted_everything\fP. Use \fBstatic\fP for just roles, environments, cookbooks, and data bags. By default, \fBeverything\fP and \fBhosted_everything\fP are dynamically selected depending on the server type. Default: \fBeverything\fP / \fBhosted_everything\fP. .UNINDENT .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/README.md0000644000004100000410000000405512254362222020226 0ustar www-datawww-data# Man pages for Knife The source of the Chef Documentation is located at http://docs.opscode.com/. This README documents how the man pages for all of the Knife subcommands that are built into the chef-client are managed. ## Source Files The source files are located in the chef-docs repository: https://github.com/opscode/chef-docs Each Knife subcommand has its own source folder. The folder naming pattern begins with man_. Each man page is a single file called index.html. In the conf.py file, the following settings are unique to each man page: `today` setting is used to define the Chef version. This is because we don't want an arbitrary date populated in the file, yet we still need a version number. For example: `today = 'Chef 11.8`. `project` setting is set to be the same as the name of the subcommand. For example: `project = u'knife-foo'`. `Options for man page output` settings are set to be similar across all man pages, but each one needs to be tailored specifically for the name of the man page. All of the other settings in the General Configuration section should be left alone. These exist to ensure that all of the doc builds are sharing the right common elements and have the same overall presentation. ## Building Docs The docs are built using Sphinx and must be set to the `-b man` output. Currently, the man pages are built locally and then added to the Chef builds in chef-master. ## Editing These files should never be edited. All of the content is pulled in from elsewhere in the chef-docs repo at build time. If changes need to be made, those changes are done elsewhere and then the man pages must be rebuilt. This is to help ensure that all of the changes are made across all of the locations in which these documents need to live. For example, by design, every Knife subcommand with a man page also has an HTML doc at docs.opscode.com/knife_foo.html. ## License [Creative Commons Attribution 3.0 Unported License](http://creativecommons.org/licenses/by/3.0/) ## Questions? Open an [Issue](https://github.com/opscode/chef-docs/issues) and ask. chef-11.8.2/distro/common/man/man1/knife-ssh.10000644000004100000410000002420112254362222020713 0ustar www-datawww-data.TH "KNIFE-SSH" "1" "Chef 11.8.0" "" "knife ssh" .SH NAME knife-ssh \- The man page for the knife ssh subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp The \fBknife ssh\fP subcommand is used to invoke SSH commands (in parallel) on a subset of nodes within an organization, based on the results of a search query. .sp \fBCommon Options\fP .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife ssh SEARCH_QUERY SSH_COMMAND (options) .ft P .fi .sp \fBOptions\fP .sp This subcommand has the following options: .INDENT 0.0 .TP .B \fB\-a SSH_ATTR\fP, \fB\-\-attribute SSH_ATTR\fP The attribute that is used when opening the SSH connection. The default attribute is the FQDN of the host. Other possible values include a public IP address, a private IP address, or a hostname. .TP .B \fB\-C NUM\fP, \fB\-\-concurrency NUM\fP The number of allowed concurrent connections. .TP .B \fB\-G GATEWAY\fP, \fB\-\-ssh\-gateway GATEWAY\fP The SSH tunnel or gateway that is used to run a bootstrap action on a machine that is not accessible from the workstation. .TP .B \fB\-i IDENTITY_FILE\fP, \fB\-\-identity\-file IDENTIFY_FILE\fP The SSH identity file used for authentication. Key\-based authentication is recommended. .TP .B \fB\-m\fP, \fB\-\-manual\-list\fP Indicates that a search query is a space\-separated list of servers. If there is more than one item in the list, put quotes around the entire list. For example: \fB\-\-manual\-list "server01 server 02 server 03"\fP .TP .B \fB\-\-[no\-]host\-key\-verify\fP Use \fB\-\-no\-host\-key\-verify\fP to disable host key verification. Default setting: \fB\-\-host\-key\-verify\fP. .TP .B \fBOTHER\fP The shell type. Possible values: \fBinteractive\fP, \fBscreen\fP, \fBtmux\fP, \fBmacterm\fP, or \fBcssh\fP. (\fBcsshx\fP is deprecated in favor of \fBcssh\fP.) .TP .B \fB\-p PORT\fP, \fB\-\-ssh\-port PORT\fP The SSH port. .TP .B \fB\-P PASSWORD\fP, \fB\-\-ssh\-password PASSWORD\fP The SSH password. This can be used to pass the password directly on the command line. If this option is not specified (and a password is required) Knife will prompt for the password. .TP .B \fBSEARCH_QUERY\fP The search query used to return a list of servers to be accessed using SSH and the specified \fBSSH_COMMAND\fP. This option uses the same syntax as the search sub\-command. .TP .B \fBSSH_COMMAND\fP The command that will be run against the results of a search query. .TP .B \fB\-x USER_NAME\fP, \fB\-\-ssh\-user USER_NAME\fP The SSH user name. .UNINDENT .sp \fBExamples\fP .sp To find the uptime of all of web servers running Ubuntu on the Amazon EC2 platform, enter: .sp .nf .ft C $ knife ssh "role:web" "uptime" \-x ubuntu \-a ec2.public_hostname .ft P .fi .sp to return something like: .sp .nf .ft C ec2\-174\-129\-127\-206.compute\-1.amazonaws.com 13:50:47 up 1 day, 23:26, 1 user, load average: 0.25, 0.18, 0.11 ec2\-67\-202\-63\-102.compute\-1.amazonaws.com 13:50:47 up 1 day, 23:33, 1 user, load average: 0.12, 0.13, 0.10 ec2\-184\-73\-9\-250.compute\-1.amazonaws.com 13:50:48 up 16:45, 1 user, load average: 0.30, 0.22, 0.13 ec2\-75\-101\-240\-230.compute\-1.amazonaws.com 13:50:48 up 1 day, 22:59, 1 user, load average: 0.24, 0.17, 0.11 ec2\-184\-73\-60\-141.compute\-1.amazonaws.com 13:50:48 up 1 day, 23:30, 1 user, load average: 0.32, 0.17, 0.15 .ft P .fi .sp To run the chef\-client on all nodes, enter: .sp .nf .ft C $ knife ssh \(aqname:*\(aq \(aqsudo chef\-client\(aq .ft P .fi .sp To force a chef\-client run on all of the web servers running Ubuntu on the Amazon EC2 platform, enter: .sp .nf .ft C $ knife ssh "role:web" "sudo chef\-client" \-x ubuntu \-a ec2.public_hostname .ft P .fi .sp to return something like: .sp .nf .ft C ec2\-67\-202\-63\-102.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:37 +0000] INFO: Starting Chef Run (Version 0.9.10) ec2\-174\-129\-127\-206.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:37 +0000] INFO: Starting Chef Run (Version 0.9.10) ec2\-184\-73\-9\-250.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:38 +0000] INFO: Starting Chef Run (Version 0.9.10) ec2\-75\-101\-240\-230.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:38 +0000] INFO: Starting Chef Run (Version 0.9.10) ec2\-184\-73\-60\-141.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:38 +0000] INFO: Starting Chef Run (Version 0.9.10) ec2\-174\-129\-127\-206.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:39 +0000] INFO: Chef Run complete in 1.419243 seconds ec2\-174\-129\-127\-206.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:39 +0000] INFO: cleaning the checksum cache ec2\-174\-129\-127\-206.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:39 +0000] INFO: Running report handlers ec2\-174\-129\-127\-206.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:39 +0000] INFO: Report handlers complete ec2\-67\-202\-63\-102.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:39 +0000] INFO: Chef Run complete in 1.578265 seconds ec2\-67\-202\-63\-102.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:39 +0000] INFO: cleaning the checksum cache ec2\-67\-202\-63\-102.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:39 +0000] INFO: Running report handlers ec2\-67\-202\-63\-102.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:39 +0000] INFO: Report handlers complete ec2\-184\-73\-9\-250.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:40 +0000] INFO: Chef Run complete in 1.638884 seconds ec2\-184\-73\-9\-250.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:40 +0000] INFO: cleaning the checksum cache ec2\-184\-73\-9\-250.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:40 +0000] INFO: Running report handlers ec2\-184\-73\-9\-250.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:40 +0000] INFO: Report handlers complete ec2\-75\-101\-240\-230.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:40 +0000] INFO: Chef Run complete in 1.540257 seconds ec2\-75\-101\-240\-230.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:40 +0000] INFO: cleaning the checksum cache ec2\-75\-101\-240\-230.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:40 +0000] INFO: Running report handlers ec2\-75\-101\-240\-230.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:40 +0000] INFO: Report handlers complete ec2\-184\-73\-60\-141.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:40 +0000] INFO: Chef Run complete in 1.502489 seconds ec2\-184\-73\-60\-141.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:40 +0000] INFO: cleaning the checksum cache ec2\-184\-73\-60\-141.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:40 +0000] INFO: Running report handlers ec2\-184\-73\-60\-141.compute\-1.amazonaws.com [Fri, 22 Oct 2010 14:18:40 +0000] INFO: Report handlers complete .ft P .fi .sp To query for all nodes that have the "webserver" role and then use SSH to run the command "sudo chef\-client", enter: .sp .nf .ft C $ knife ssh "role:webserver" "sudo chef\-client" .ft P .fi .sp To upgrade all nodes, enter: .sp .nf .ft C $ knife ssh name:* "sudo aptitude upgrade \-y" .ft P .fi .sp To specify the shell type used on the nodes returned by a search query: .sp .nf .ft C $ knife ssh roles:opscode\-omnitruck macterm .ft P .fi .sp where \fBscreen\fP is one of the following values: \fBcssh\fP, \fBinteractive\fP, \fBmacterm\fP, \fBscreen\fP, or \fBtmux\fP. If the node does not have the shell type installed, Knife will return an error similar to the following: .sp .nf .ft C you need the rb\-appscript gem to use knife ssh macterm. \(ga(sudo) gem install rb\-appscript\(ga to install ERROR: LoadError: cannot load such file \-\- appscript .ft P .fi .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/man/man1/knife-xargs.10000644000004100000410000001312712254362222021247 0ustar www-datawww-data.TH "KNIFE-XARGS" "1" "Chef 11.8.0" "" "knife xargs" .SH NAME knife-xargs \- The man page for the knife xargs subcommand. . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .\" Man page generated from reStructuredText. . .sp The \fBknife xargs\fP subcommand is used to build and execute command lines against objects on a server using standard input. .sp \fBCommon Options\fP .sp The following options can be run with all Knife sub\-commands and plug\-ins: .INDENT 0.0 .TP .B \fB\-c CONFIG\fP, \fB\-\-config CONFIG\fP The configuration file to use. .TP .B \fB\-\-color\fP Indicates that colored output will be used. .TP .B \fB\-d\fP, \fB\-\-disable\-editing\fP Indicates that $EDITOR will not be opened; data will be accepted as\-is. .TP .B \fB\-\-defaults\fP Indicates that Knife will use the default value, instead of asking a user to provide one. .TP .B \fB\-e EDITOR\fP, \fB\-\-editor EDITOR\fP The $EDITOR that is used for all interactive commands. .TP .B \fB\-E ENVIRONMENT\fP, \fB\-\-environment ENVIRONMENT\fP The name of the environment. When this option is added to a command, the command will run only against the named environment. .TP .B \fB\-f FILE_NAME\fP, \fB\-\-file FILE_NAME\fP Indicates that the private key will be saved to a specified file name. .TP .B \fB\-F FORMAT\fP, \fB\-\-format FORMAT\fP The output format: \fBsummary\fP (default), \fBtext\fP, \fBjson\fP, \fByaml\fP, and \fBpp\fP. .TP .B \fB\-h\fP, \fB\-\-help\fP Shows help for the command. .TP .B \fB\-k KEY\fP, \fB\-\-key KEY\fP The private key that Knife will use to sign requests made by the API client to the server. .TP .B \fB\-\-no\-color\fP Indicates that color will not be used in the output. .TP .B \fB\-p PASSWORD\fP, \fB\-\-password PASSWORD\fP The user password. .TP .B \fB\-\-print\-after\fP Indicates that data will be shown after a destructive operation. .TP .B \fB\-s URL\fP, \fB\-\-server\-url URL\fP The URL for the server. .TP .B \fB\-u USER\fP, \fB\-\-user USER\fP The user name used by Knife to sign requests made by the API client to the server. Authentication will fail if the user name does not match the private key. .TP .B \fB\-v\fP, \fB\-\-version\fP The version of the chef\-client. .TP .B \fB\-V\fP, \fB\-\-verbose\fP Set for more verbose outputs. Use \fB\-VV\fP for maximum verbosity. .TP .B \fB\-y\fP, \fB\-\-yes\fP Indicates that the response to all confirmation prompts will be "Yes" (and that Knife will not ask for confirmation). .UNINDENT .sp \fBSyntax\fP .sp This argument has the following syntax: .sp .nf .ft C $ knife xargs [PATTERN...] (options) .ft P .fi .sp \fBOptions\fP .sp This subcommand has the following options: .INDENT 0.0 .TP .B \fB\-0\fP Indicates that a \fBNULL\fP character (\fB\e0\fP) will be used as a separator, instead of white space. Default: \fBfalse\fP. .TP .B \fB\-\-chef\-repo\-path PATH\fP The path to the chef\-repo. This setting will override the default path to the chef\-repo. Default: same as specified by \fBchef_repo_path\fP in config.rb. .TP .B \fB\-\-concurrency\fP The number of allowed concurrent connections. Default: \fB10\fP. .TP .B \fB\-\-[no\-]diff\fP Use to show a diff when a file changes. Default: \fB\-\-diff\fP. .TP .B \fB\-\-dry\-run\fP Use to prevent changes from being uploaded to the server. Default: \fBfalse\fP. .TP .B \fB\-\-[no\-]force\fP Use to force the upload of files even if they haven\(aqt been changed. Default: \fB\-\-no\-force\fP. .TP .B \fB\-\-local\fP Indicates that a command line will be built or executed against a local file. Set to \fBfalse\fP to build or execute against a remote file. Default: \fBfalse\fP. .TP .B \fB\-n MAX_ARGS\fP, \fB\-\-max\-args MAX_ARGS\fP The maximum number of arguments per command line. Default: \fBnil\fP. .TP .B \fB\-s LENGTH\fP, \fB\-\-max\-chars LENGTH\fP The maximum size (in characters) for a command line. Default: \fBnil\fP. .TP .B \fB\-p [PATTERN...]\fP, \fB\-\-pattern [PATTERN...]\fP One (or more) patterns for a command line. If this option is not specified, a list of patterns may be expected on standard input. Default: \fBnil\fP. .TP .B \fB\-I REPLACE_STRING\fP, \fB\-\-replace REPLACE_STRING\fP Use to define a string that will be used to replace all occurrences of a file name. Default: \fBnil\fP. .TP .B \fB\-J REPLACE_STRING\fP, \fB\-\-replace\-first REPLACE_STRING\fP Use to define a string that will be used to replace the first occurrence of a file name. Default: \fBnil\fP. .TP .B \fB\-\-repo\-mode MODE\fP The layout of the local chef\-repo. Possible values: \fBstatic\fP, \fBeverything\fP, or \fBhosted_everything\fP. Use \fBstatic\fP for just roles, environments, cookbooks, and data bags. By default, \fBeverything\fP and \fBhosted_everything\fP are dynamically selected depending on the server type. Default value: \fBdefault\fP. .TP .B \fB\-t\fP Indicates that the print command will be run on the command line. Default: \fBnil\fP. .UNINDENT .sp \fBExamples\fP .sp To use the output of \fBknife deps\fP to pass a command to \fBknife xargs\fP. For example: .sp .nf .ft C $ knife deps nodes/*.json | xargs knife upload .ft P .fi .SH AUTHOR Opscode .\" Generated by docutils manpage writer. . chef-11.8.2/distro/common/markdown/0000755000004100000410000000000012254362222017156 5ustar www-datawww-datachef-11.8.2/distro/common/markdown/man8/0000755000004100000410000000000012254362222020021 5ustar www-datawww-datachef-11.8.2/distro/common/markdown/man8/chef-expanderctl.mkd0000644000004100000410000000344312254362222023736 0ustar www-datawww-datachef-expanderctl(8) -- management program for chef-expander ======================================== ## SYNOPSIS __chef-expanderctl__ _COMMAND_ __Commands:__ * `help`: Show help message * `queue-depth`: display the aggregate queue backlog * `queue-status`: show the backlog and consumer count for each vnode queue * `node-status`: show the status of the nodes in the cluster * `log-level`: sets the log level of all nodes in the cluster ## DESCRIPTION Chef-expanderctl is a management program that allows you to get status information or change the logging verbosity (without restarting). chef-expanderctl has the following commands: * __chef-expanderctl help__ prints usage. * __chef-expanderctl queue-depth__ Shows the total number of messages in the queues. * __chef-expanderctl queue-status__ Show the number of messages in each queue. This is mainly of use when debugging a Chef Expander cluster. * __chef-expanderctl log-level LEVEL__ Sets the log level on a running Chef Expander or cluster. If you suspect that a worker process is stuck, as long as you are using clustered operation, you can simply kill the worker process and it will be restarted by the master process. ## SEE ALSO __chef-expander-cluster__(8) __chef-solr__(8) Full documentation for Chef and chef-server is located on the Chef wiki, http://wiki.opscode.com/display/chef/Home. ## AUTHOR Chef was written by Adam Jacob of Opscode (http://www.opscode.com), with contributions from the community. This manual page was created by Nuo Yan . Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. On Debian systems, the complete text of the Apache 2.0 License can be found in /usr/share/common-licenses/Apache-2.0. chef-11.8.2/distro/common/markdown/man8/chef-server-webui.mkd0000644000004100000410000001210412254362222024036 0ustar www-datawww-datachef-server-webui(8) -- Start the Chef Server merb application slice providing Web User Interface (Management Console). ======================================== ## SYNOPSIS __chef-server-webui__ _(options)_ * `-u`, `--user USER`: This flag is for having chef-server-webui run as a user other than the one currently logged in. Note: if you set this you must also provide a --group option for it to take effect. * `-G`, `--group GROUP`: This flag is for having chef-server-webui run as a group other than the one currently logged in. Note: if you set this you must also provide a --user option for it to take effect. * `-d`, `--daemonize`: This will run a single chef-server-webui in the background. * `-N`, `--no-daemonize`: This will allow you to run a cluster in console mode. * `-c`, `--cluster-nodes NUM_MERBS`: Number of merb daemons to run for chef-server-webui. * `-I`, `--init-file FILE`: File to use for initialization on load, defaults to config/init.rb. * `-p`, `--port PORTNUM`: Port to run chef-server-webui on, defaults to 4040. Additional nodes (-c) listen on incrementing port numbers. * `-o`, `--socket-file FILE`: Socket file to run chef-server-webui on, defaults to [Merb.root]/log/merb.sock. This is for web servers, like thin, that use sockets. Specify this *only* if you *must*. * `-s`, `--socket SOCKNUM`: Socket number to run chef-server-webui on, defaults to 0. * `-n`, `--name NAME`: Set the name of the application. This is used in the process title and log file names. * `-P`, `--pid PIDFILE`: PID file, defaults to [Merb.root]/log/merb.main.pid for the master process and[Merb.root]/log/merb.[port number].pid for worker processes. For clusters, use %s to specify where in the file chef-server-webui should place the port number. For instance: -P myapp.%s.pid. * `-h`, `--host HOSTNAME`: Host to bind to (default is 0.0.0.0). * `-m`, `--merb-root PATH_TO_APP_ROOT`: The path to the Merb.root for the app you want to run (default is current working directory). * `-a`, `--adapter ADAPTER`: The rack adapter to use to run chef-server-webui (default is mongrel) [mongrel, emongrel, thin, ebb, fastcgi, webrick]. * `-R`, `--rackup FILE`: Load an alternate Rack config file (default is config/rack.rb). * `-i`, `--irb-console`: This flag will start chef-server-webui in irb console mode. All your models and other classes will be available for you in an irb session. * `-S`, `--sandbox`: This flag will enable a sandboxed irb console. If your ORM supports transactions, all edits will be rolled back on exit. * `-l`, `--log-level LEVEL`: Log levels can be set to any of these options: debug < info < warn < error < fatal (default is info). * `-L`, `--log LOGFILE`: A string representing the logfile to use. Defaults to [Merb.root]/log/merb.[main].log for the master process and [Merb.root]/log/merb[port number].logfor worker processes. * `-e`, `--environment STRING`: Environment to run Merb under [development, production, testing] (default is development). * `-r`, `--script-runner ['RUBY CODE'| FULL_SCRIPT_PATH]`: Command-line option to run scripts and/or code in the chef-server-webui app. * `-K`, `-graceful PORT or all`: Gracefully kill chef-server-webui proceses by port number. Use chef-server -K all to gracefully kill all merbs. * `-k`, `--kill PORT`: Force kill one merb worker by port number. This will cause the worker to be respawned. * `--fast-deploy`: Reload the code, but not yourinit.rb or gems. * `-X`, `--mutex on/off`: This flag is for turning the mutex lock on and off. * `-D`, `--debugger`: Run chef-server-webui using rDebug. * `-V`, `--verbose`: Print extra information. * `-C`, `--console-trap`: Enter an irb console on ^C. * `-?`, `-H`, `--help`: Show this help message. ## DESCRIPTION The Chef Server WebUI (Management Console) is a Merb application slice. The default listen port is 4040. The Management Console is Chef Server's web interface. Nodes, roles, cookbooks, data bags, and API clients can be managed through the Management Console. Search can also be done on the console. In order to start using the Management Console, you need to first create a user or change the default password on the "admin" user. The default credentials are: - `Username`: admin - `Password`: p@ssw0rd1 ## SEE ALSO Full documentation for Chef and chef-server-webui (Management Console) is located on the Chef wiki, http://wiki.opscode.com/display/chef/Home. ## AUTHOR Chef was written by Adam Jacob of Opscode (http://www.opscode.com), with contributions from the community. This manual page was written by Joshua Timberman with help2man for the Debian project (but may be used by others). Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. On Debian systems, the complete text of the Apache 2.0 License can be found in /usr/share/common-licenses/Apache-2.0. chef-11.8.2/distro/common/markdown/man8/chef-solo.mkd0000644000004100000410000000744012254362222022402 0ustar www-datawww-datachef-solo(8) -- Runs chef in solo mode against a specified cookbook location. ======================================== ## SYNOPSIS __chef-solo__ _(options)_ * `-c`, `--config CONFIG`: The configuration file to use * `-d`, `--daemonize`: Daemonize the process * `-g`, `--group GROUP`: Group to set privilege to * `-i`, `--interval SECONDS`: Run chef-client periodically, in seconds * `-j`, `--json-attributes JSON_ATTRIBS`: Load attributes from a JSON file or URL * `-l`, `--log_level LEVEL`: Set the log level (debug, info, warn, error, fatal) * `-L`, `--logfile LOGLOCATION`: Set the log file location, defaults to STDOUT - recommended for daemonizing * `-N`, `--node-name NODE_NAME`: The node name for this client * `-r`, `--recipe-url RECIPE_URL`: Pull down a remote gzipped tarball of recipes and untar it to the cookbook cache. * `-s`, `--splay SECONDS`: The splay time for running at intervals, in seconds * `-u`, `--user USER`: User to set privilege to * `-v`, `--version`: Show chef version * `-h`, `--help`: Show this message ## DESCRIPTION Chef Solo allows you to run Chef Cookbooks in the absence of a Chef Server. To do this, the complete cookbook needs to be present on disk. By default Chef Solo will look in /etc/chef/solo.rb for its configuration. This configuration file has two required variables: file_cache_path and cookbook_path. For example: file_cache_path "/var/chef-solo" cookbook_path "/var/chef-solo/cookbooks" For your own systems, you can change this to reflect any directory you like, but you'll need to specify absolute paths and the cookbook_path directory should be a subdirectory of the file_cache_path. You can also specify cookbook_path as an array, passing multiple locations to search for cookbooks. For example: file_cache_path "/var/chef-solo" cookbook_path ["/var/chef-solo/cookbooks", "/var/chef-solo/site-cookbooks"] Note that earlier entries are now overridden by later ones. Since chef-solo doesn't have any interaction with a Chef Server, you'll need to specify node-specifc attributes in a JSON file. This can be located on the target system itself, or it can be stored on a remote server such as S3, or a web server on your network. Within the JSON file, you'll also specify the recipes that Chef should run in the "run_list". An example JSON file, which sets a resolv.conf: { "resolver": { "nameservers": [ "10.0.0.1" ], "search":"int.example.com" }, "run_list": [ "recipe[resolver]" ] } Then you can run chef-solo with -j to specify the JSON file. It will look for cookbooks in the cookbook_path configured in the configuration file, and apply attributes and use the run_list from the JSON file specified. You can use -c to specify the path to the configuration file (if you don't want chef-solo to use the default). You can also specify -r for a cookbook tarball. For example: chef-solo -c ~/solo.rb -j ~/node.json -r http://www.example.com/chef-solo.tar.gz In the above case, chef-solo would extract the tarball to your specified cookbook_path, use ~/solo.rb as the configuration file, and apply attributes and use the run_list from ~/node.json. ## SEE ALSO Full documentation for Chef and chef-solo is located on the Chef wiki, http://wiki.opscode.com/display/chef/Home. ## AUTHOR Chef was written by Adam Jacob of Opscode (http://www.opscode.com), with contributions from the community. This manual page was written by Joshua Timberman with help2man. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. On Debian systems, the complete text of the Apache 2.0 License can be found in /usr/share/common-licenses/Apache-2.0. chef-11.8.2/distro/common/markdown/man8/chef-expander.mkd0000644000004100000410000000534612254362222023237 0ustar www-datawww-datachef-expander(8) -- fetches messages from RabbitMQ, processes, and loads into chef-solr ======================================== ## SYNOPSIS __chef-expander__ _(options)_ * `-c`, `--config CONFIG_FILE`: a configuration file to use * `-i`, `--index INDEX`: the slot this node will occupy in the ring * `-n`, `--node-count NUMBER`: the number of nodes in the ring * `-l`, `--log-level LOG_LEVEL`: set the log level * `-L`, `--logfile LOG_LOCATION`: Logfile to use * `-d`, `--daemonize`: fork into the background * `-P`, `--pid PIDFILE`: PID file * `-h`, `--help`: show help message * `-v`, `--version`: show the version and exit ## DESCRIPTION Chef Expander fetches messages from RabbitMQ, processes them into the correct format to be loaded into Solr and loads them into Solr. __Running Chef Expander__ Chef Expander is designed for clustered operation, though small installations will only need one worker process. To run Chef Expander with one worker process, run chef-expander -n 1. You will then have a master and worker process, which looks like this in ps: your-shell> ps aux|grep expander you 52110 0.1 0.7 2515476 62748 s003 S+ 3:49PM 0:00.80 chef-expander worker #1 (vnodes 0-1023) you 52108 0.1 0.5 2492880 41696 s003 S+ 3:49PM 0:00.91 ruby bin/chef-expander -n 1 Workers are single threaded and therefore cannot use more than 100% of a single CPU. If you find that your queues are getting backlogged, increase the number of workers __Design__ Chef Expander uses 1024 queues (called vnodes in some places) to allow you to scale the number of Chef Expander workers to meet the needs of your infrastructure. When objects are saved in the API server, they are added to queues based on their database IDs. These queues can be assigned to different Chef Expander workers to distribute the load of processing the index updates. __Chef Expander Operation and Troubleshooting__ Chef Expander includes chef-expanderctl, a management program that allows you to get status information or change the logging verbosity (without restarting). See __chef-expanderctl__(8) for details. ## SEE ALSO __chef-expanderctl__(8) __chef-solr__(8) Full documentation for Chef and chef-server is located on the Chef wiki, http://wiki.opscode.com/display/chef/Home. ## AUTHOR Chef was written by Adam Jacob of Opscode (http://www.opscode.com), with contributions from the community. This manual page was created by Nuo Yan . Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. On Debian systems, the complete text of the Apache 2.0 License can be found in /usr/share/common-licenses/Apache-2.0. chef-11.8.2/distro/common/markdown/man8/chef-solr.mkd0000644000004100000410000000577612254362222022417 0ustar www-datawww-datachef-solr(8) -- Runs as Chef's search server ======================================== ## SYNOPSIS __chef-solr__ _(options)_ * `-c`, `--config CONFIG`: The configuration file to use * `-d`, `--daemonize`: Daemonize the process * `-g`, `--group GROUP`: Group to set privilege to * `-l`, `--log_level LEVEL`: Set the log level (debug, info, warn, error, fatal) * `-L`, `--logfile LOGLOCATION`: Set the log file location, defaults to STDOUT - recommended for daemonizing * `-P`, `--pid PIDFILE`: Set the PID file location, defaults to /tmp/chef-solr.pid * `-D`, `--solr-data-dir PATH`: Where the Solr data lives * `-x`, `--solor-heap-size SIZE`: Set the size of the Java Heap * `-H`, `--solr-home-dir PATH`: Solr home directory * `-j`, `--java-opts OPTS`: Raw options passed to Java * `-x`, `--solor-heap-size`: Set the size of the Java Heap * `-W`, `--solr-jetty-dir PATH`: Where to place the Solr Jetty instance * `-u`, `--user USER`: User to set privilege to * `-v`, `--version`: Show chef-solr version * `-h`, `--help`: Show this message ## DESCRIPTION Chef-solr provides search service for Chef. You need to have both chef-solr and chef-expander-cluster running in order for search to work. __Installation__ Make sure you backed up your data if you are upgrading from a previous version. Run chef-solr-installer to upgrade your Chef Solr installation. Answer "yes" when prompted for confirmation. The process should look like this: yourshell> chef-solr-installer Configuration setting solr_heap_size is unknown and will be ignored Chef Solr is already installed in /var/chef/solr Do you want to overwrite the current install? All existing Solr data will be lost. [y/n] y Removing the existing Chef Solr installation rm -rf /var/chef/solr rm -rf /var/chef/solr-jetty rm -rf /var/chef/solr/data Creating Solr Home Directory mkdir -p /var/chef/solr entering /var/chef/solr tar zxvf /Users/ddeleo/opscode/chef/chef-solr/solr/solr-home.tar.gz Creating Solr Data Directory mkdir -p /var/chef/solr/data Unpacking Solr Jetty mkdir -p /var/chef/solr-jetty entering /var/chef/solr-jetty tar zxvf /Users/ddeleo/opscode/chef/chef-solr/solr/solr-jetty.tar.gz Successfully installed Chef Solr. You can restore your search index using `knife index rebuild` ## SEE ALSO __chef-expander-cluster__(8) Full documentation for Chef and chef-server is located on the Chef wiki, http://wiki.opscode.com/display/chef/Home. ## AUTHOR Chef was written by Adam Jacob of Opscode (http://www.opscode.com), with contributions from the community. This manual page was written by Joshua Timberman with help2man. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. On Debian systems, the complete text of the Apache 2.0 License can be found in /usr/share/common-licenses/Apache-2.0. chef-11.8.2/distro/common/markdown/man8/chef-server.mkd0000644000004100000410000001207512254362222022734 0ustar www-datawww-datachef-server(8) - Start the Chef Server merb application slice. ======================================== ## SYNOPSIS __chef-server__ _(options)_ * `-u`, `--user USER`: This flag is for having chef-server-webui run as a user other than the one currently logged in. Note: if you set this you must also provide a --group option for it to take effect. * `-G`, `--group GROUP`: This flag is for having chef-server-webui run as a group other than the one currently logged in. Note: if you set this you must also provide a --user option for it to take effect. * `-d`, `--daemonize`: This will run a single chef-server-webui in the background. * `-N`, `--no-daemonize`: This will allow you to run a cluster in console mode. * `-c`, `--cluster-nodes NUM_MERBS`: Number of merb daemons to run for chef-server-webui. * `-I`, `--init-file FILE`: File to use for initialization on load, defaults to config/init.rb. * `-p`, `--port PORTNUM`: Port to run chef-server-webui on, defaults to 4040. Additional nodes (-c) listen on incrementing port numbers. * `-o`, `--socket-file FILE`: Socket file to run chef-server-webui on, defaults to [Merb.root]/log/merb.sock. This is for web servers, like thin, that use sockets. Specify this *only* if you *must*. * `-s`, `--socket SOCKNUM`: Socket number to run chef-server-webui on, defaults to 0. * `-n`, `--name NAME`: Set the name of the application. This is used in the process title and log file names. * `-P`, `--pid PIDFILE`: PID file, defaults to [Merb.root]/log/merb.main.pid for the master process and[Merb.root]/log/merb.[port number].pid for worker processes. For clusters, use %s to specify where in the file chef-server-webui should place the port number. For instance: -P myapp.%s.pid. * `-h`, `--host HOSTNAME`: Host to bind to (default is 0.0.0.0). * `-m`, `--merb-root PATH_TO_APP_ROOT`: The path to the Merb.root for the app you want to run (default is current working directory). * `-a`, `--adapter ADAPTER`: The rack adapter to use to run chef-server-webui (default is mongrel) [mongrel, emongrel, thin, ebb, fastcgi, webrick]. * `-R`, `--rackup FILE`: Load an alternate Rack config file (default is config/rack.rb). * `-i`, `--irb-console`: This flag will start chef-server-webui in irb console mode. All your models and other classes will be available for you in an irb session. * `-S`, `--sandbox`: This flag will enable a sandboxed irb console. If your ORM supports transactions, all edits will be rolled back on exit. * `-l`, `--log-level LEVEL`: Log levels can be set to any of these options: debug < info < warn < error < fatal (default is info). * `-L`, `--log LOGFILE`: A string representing the logfile to use. Defaults to [Merb.root]/log/merb.[main].log for the master process and [Merb.root]/log/merb[port number].logfor worker processes. * `-e`, `--environment STRING`: Environment to run Merb under [development, production, testing] (default is development). * `-r`, `--script-runner ['RUBY CODE'| FULL_SCRIPT_PATH]`: Command-line option to run scripts and/or code in the chef-server-webui app. * `-K`, `-graceful PORT or all`: Gracefully kill chef-server-webui proceses by port number. Use chef-server -K all to gracefully kill all merbs. * `-k`, `--kill PORT`: Force kill one merb worker by port number. This will cause the worker to be respawned. * `--fast-deploy`: Reload the code, but not yourinit.rb or gems. * `-X`, `--mutex on/off`: This flag is for turning the mutex lock on and off. * `-D`, `--debugger`: Run chef-server-webui using rDebug. * `-V`, `--verbose`: Print extra information. * `-C`, `--console-trap`: Enter an irb console on ^C. * `-?`, `-H`, `--help`: Show this help message. ## DESCRIPTION The Chef Server provides a central point for the distribution of Cookbooks, management and authentication of Nodes, and the use of Search. It provides a REST API. The API service is what clients use to interact with the server to manage node configuration in Chef. By default, the service is started on port 4000 as a Merb application slice running with the thin server adapter. The two methods of interaction with the API for humans are the command-line tool Knife and the Management Console. The Chef Client library is used for interacting with the API for client nodes. ## SEE ALSO __chef-client__(8) __chef-server-webui__(8) __knife__(1) Full documentation for Chef and chef-server is located on the Chef wiki, http://wiki.opscode.com/display/chef/Home. ## AUTHOR Chef was written by Adam Jacob of Opscode (http://www.opscode.com), with contributions from the community. This manual page was written by Joshua Timberman with help2man. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. On Debian systems, the complete text of the Apache 2.0 License can be found in /usr/share/common-licenses/Apache-2.0. chef-11.8.2/distro/common/markdown/man8/chef-client.mkd0000644000004100000410000000511712254362222022703 0ustar www-datawww-datachef-client(8) -- Runs a client node connecting to a chef-server. ======================================== ## SYNOPSIS __chef-client__ _(options)_ * `-S`, `--server CHEFSERVERURL`: The chef server URL * `-c`, `--config CONFIG`: The configuration file to use * `-d`, `--daemonize`: Daemonize the process * `-g`, `--group GROUP`: Group to set privilege to * `-i`, `--interval SECONDS`: Run chef-client periodically, in seconds * `-j`, `--json-attributes JSON_ATTRIBS`: Load attributes from a JSON file or URL * `-E`, `--environment ENVIRONMENT`: Set the Chef Environment on the node * `-l`, `--log_level LEVEL`: Set the log level (debug, info, warn, error, fatal) * `-L`, `--logfile LOGLOCATION`: Set the log file location, defaults to STDOUT - recommended for daemonizing * `-N`, `--node-name NODE_NAME`: The node name for this client * `-o`, `--override-runlist`: Replace current run list with specified items * `-K`, `--validation_key KEY_FILE`: Set the validation key file location, used for registering new clients * `-k`, `--client_key KEY_FILE`: Set the client key file location * `-s`, `--splay SECONDS`: The splay time for running at intervals, in seconds * `-u`, `--user USER`: User to set privilege to * `-P`, `--pid PIDFILE`: Set the PID file location, defaults to /tmp/chef-client.pid * `--once`: Cancel any interval or splay options, run chef once and exit * `-v`, `--version`: Show chef version * `-h`, `--help`: Show this message ## DESCRIPTION The Chef Client is where almost all of the work in Chef is done. It communicates with the Chef Server via REST, authenticates via Signed Header Authentication, and compiles and executes Cookbooks. A Chef Client does work on behalf of a Node. A single Chef Client can run recipes for multiple Nodes. Clients are where all the action happens - the Chef Server and Chef Expander are largely services that exist only to provide the Client with information. ## SEE ALSO Full documentation for Chef and chef-client is located on the Chef wiki, http://wiki.opscode.com/display/chef/Home. ## AUTHOR Chef was written by Adam Jacob of Opscode (http://www.opscode.com), with contributions from the community. This manual page was written by Joshua Timberman with help2man. Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. On Debian systems, the complete text of the Apache 2.0 License can be found in /usr/share/common-licenses/Apache-2.0. chef-11.8.2/distro/common/markdown/README0000644000004100000410000000023712254362222020040 0ustar www-datawww-dataThis directory contains markdown documentation that is used in other places. For example, markdown (.mkd) documents that are generated as man pages with ronn. chef-11.8.2/distro/common/markdown/man1/0000755000004100000410000000000012254362222020012 5ustar www-datawww-datachef-11.8.2/distro/common/markdown/man1/knife-status.mkd0000644000004100000410000000227712254362222023134 0ustar www-datawww-dataknife-status(1) -- Display status information for the nodes in your infrastructure ======================================== ## SYNOPSIS __knife__ __status__ _(options)_ * `-r`, `--run-list RUN_LIST`: Show the run list ## DESCRIPTION The _status_ sub-command searches the Chef Server for all nodes and displays information about the last time the node checked into the server and executed a `node.save`. The fields displayed are the relative checkin time, the node name, it's operating system platform and version, the fully-qualified domain name and the default IP address. If the `-r` option is given, the node's run list will also be displayed. Note that depending on the configuration of the nodes, the FQDN and IP displayed may not be publicly reachable. ## SEE ALSO __knife-search__(1) ## AUTHOR Chef was written by Adam Jacob with many contributions from the community. ## DOCUMENTATION This manual page was written by Joshua Timberman . Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. ## CHEF Knife is distributed with Chef. chef-11.8.2/distro/common/markdown/man1/knife-node.mkd0000644000004100000410000001072412254362222022532 0ustar www-datawww-dataknife-node(1) -- Manage the hosts in your infrastructure ======================================== ## SYNOPSIS __knife__ __node__ _sub-command_ _(options)_ ## DESCRIPTION Nodes are data structures that represent hosts configured with Chef. Nodes have a __name__, a String that uniquely identifies the node, __attributes__, a nested Hash of properties that describe how the host should be configured, a __chef\_environment__, a String representing the environment to which the node belongs, and a __run\_list__, an ordered list of __recipes__ or __roles__ that chef-client should apply when configuring a host. When a host communicates with a Chef Server, it authenticates using its __node\_name__ for identification and signs its reqests with a private key. The Server validates the request by looking up a __client__ object with a name identical to the __node\_name__ submitted with the request and verifes the signature using the public key for that __client__ object. __NOTE__ that the __client__ is a different object in the system. It is associated with a node by virtue of having a matching name. By default __chef-client__(8) will create a node using the FQDN of the host for the node name, though this may be overridden by configuration settings. ## NODE SUB-COMMANDS The following `node` subcommands are available: ## BULK DELETE __knife node bulk delete__ _regex_ _(options)_ Deletes nodes for which the name matches the regular expression _regex_ on the Chef Server. The regular expression should be given in quotes, and should not be surrounded with forward slashes (as is typical of regular expression literals in scripting languages). ## CREATE __knife node create__ _name_ _(options)_ Create a new node. Unless the --disable-editing option is given, an empty node object will be created and displayed in your text editor. If the editor exits with a successful exit status, the node data will be posted to the Chef Server to create the node. ## DELETE __knife node delete__ _name_ _(options)_ Deletes the node identified by _name_ on the Chef Server. ## EDIT __knife node edit__ _name_ _(options)_ * `-a`, `--all`: Display all node data in the editor. By default, default, override, and automatic attributes are not shown. Edit the node identified by _name_. Like __knife node create__, the node will be displayed in your text editor unless the -n option is present. ## FROM FILE __knife node from file__ _file_ _(options)_ Create a node from a JSON format _file_. ## LIST __knife node list__ _(options)_ * `-w`, `--with-uri`: Show corresponding URIs List all nodes. ## RUN\_LIST ADD __knife node run_list add__ _name_ _run list item_ _(options)_ * `-a`, `--after ITEM`: Place the ENTRY in the run list after ITEM Add the _run list item_ to the node's `run_list`. See Run list ## RUN\_LIST REMOVE __knife node run_list remove__ _node name_ _run list item_ _(options)_ Remove the _run list item_ from the node's `run_list`. ## SHOW __knife node show__ _node name_ _(options)_ * `-a`, `--attribute [ATTR]`: Show only one attribute * `-r`, `--run-list `: Show only the run list * `-F`, `--format FORMAT`: Display the node in a different format. * `-m`, `--medium`: Display more, but not all, of the node's data when using the default _summary_ format Displays the node identified by _node name_ on stdout. ## RUN LIST ITEM FORMAT Run list items may be either roles or recipes. When adding a role to a run list, the correct syntax is "role[ROLE\_NAME]" When adding a recipe to a run list, there are several valid formats: * Fully Qualified Format: "recipe[COOKBOOK::RECIPE\_NAME]", for example, "recipe[chef::client]" * Cookbook Recipe Format: For brevity, the recipe part of the fully qualified format may be omitted, and recipes specified as "COOKBOOK::RECIPE\_NAME", e.g., "chef::client" * Default Recipe Format: When adding the default recipe of a cookbook to a run list, the recipe name may be omitted as well, e.g., "chef::default" may be written as just "chef" ## SEE ALSO __knife-client__(1) __knife-search__(1) __knife-role__(1) ## AUTHOR Chef was written by Adam Jacob with many contributions from the community. ## DOCUMENTATION This manual page was written by Joshua Timberman . Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. ## CHEF Knife is distributed with Chef. chef-11.8.2/distro/common/markdown/man1/knife-exec.mkd0000644000004100000410000000247312254362222022533 0ustar www-datawww-dataknife-exec(1) -- Run user scripts using the Chef API DSL ======================================== ## SYNOPSIS __knife__ __exec__ _(options)_ * `-E`, `--exec CODE`: Provide a snippet of code to evaluate on the command line ## DESCRIPTION `knife exec` runs arbitrary ruby scripts in a context similar to that of the chef-shell(1) DSL. See the chef-shell documentation for a description of the commands available. ## EXAMPLES * Make an API call against an arbitrary endpoint: knife exec -E 'api.get("nodes/fluke.localdomain/cookbooks")' => list of cookbooks for the node _fluke.localdomain_ * Remove the role _obsolete_ from all nodes: knife exec -E 'nodes.transform(:all){|n| n.run\_list.delete("role[obsolete]")}' * Generate the expanded run list for hosts in the `webserver` role: knife exec -E 'nodes.find(:roles => "webserver") {|n| n.expand!; n[:recipes]}' ## SEE ALSO __chef-shell(1)__ ## AUTHOR Chef was written by Adam Jacob with many contributions from the community. ## DOCUMENTATION This manual page was written by Joshua Timberman . Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. ## CHEF Knife is distributed with Chef. chef-11.8.2/distro/common/markdown/man1/knife-role.mkd0000644000004100000410000000445212254362222022547 0ustar www-datawww-dataknife-role(1) -- Group common configuration settings ======================================== ## SYNOPSIS __knife__ __role__ _sub-command_ _(options)_ ## ROLE SUB-COMMANDS The following `role` subcommands are available: ## LIST __knife role list__ _(options)_ * `-w`, `--with-uri`: Show corresponding URIs List roles. ## SHOW __knife role show ROLE__ _(options)_ * `-a`, `--attribute ATTR`: Show only one attribute Show a specific role. ## CREATE __knife role create ROLE__ _(options)_ * `-d`, `--description`: The role description Create a new role. ## EDIT __knife role edit ROLE__ _(options)_ Edit a role. ## FROM FILE __knife role from file FILE__ _(options)_ Create or update a role from a role Ruby DSL (`.rb`) or JSON file. ## DELETE __knife role delete ROLE__ _(options)_ Delete a role. ## BULK DELETE __knife role bulk delete REGEX__ _(options)_ Delete roles on the Chef Server based on a regular expression. The regular expression (_REGEX_) should be in quotes, not in //'s. ## DESCRIPTION Roles provide a mechanism to group repeated configuration settings. Roles are data structures that contain __default\_attributes__, and __override_attributes__, which are nested hashes of configuration settings, and a __run_list__, which is an ordered list of recipes and roles that should be applied to a host by chef-client. __default_attributes__ will be overridden if they conflict with a value on a node that includes the role. Conversely, __override_attributes__ will override any values set on nodes that apply them. When __chef-client__(8) configures a host, it will "expand" the __run_list__ included in that host's node data. The expansion process will recursively replace any roles in the run\_list with that role's run\_list. ## SEE ALSO __knife-node(1)__ __knife-environment(1)__ ## AUTHOR Chef was written by Adam Jacob with many contributions from the community. ## DOCUMENTATION This manual page was written by Joshua Timberman . Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. ## CHEF Knife is distributed with Chef. chef-11.8.2/distro/common/markdown/man1/knife-cookbook-site.mkd0000644000004100000410000001022412254362222024350 0ustar www-datawww-dataknife-cookbook-site(1) -- Install and update open source cookbooks ======================================== ## SYNOPSIS __knife__ __cookbook site__ _sub-command_ _(options)_ ## COOKBOOK SITE SUB-COMMANDS `knife cookbook site` provides the following subcommands: ## INSTALL __cookbook site install COOKBOOK [VERSION]__ _(options)_ * `-D`, `--skip-dependencies `: Skip automatic installation of dependencies. * `-o`, `--cookbook-path PATH`: Install cookbooks to PATH * `-B`, `--branch BRANCH`: Default branch to work with [defaults to master] Uses git(1) version control in conjunction with the cookbook site to install community contributed cookbooks to your local cookbook repository. Running `knife cookbook site install` does the following: 1. A new "pristine copy" branch is created in git for tracking the upstream; 2. All existing cookbooks are removed from the branch; 3. The cookbook is downloaded from the cookbook site in tarball form; 4. The downloaded cookbook is untarred, and its contents commited via git; 5. The pristine copy branch is merged into the master branch. By installing cookbook with this process, you can locally modify the upstream cookbook in your master branch and let git maintain your changes as a separate patch. When an updated upstream version becomes available, you will be able to merge the upstream changes while maintaining your local modifications. Unless _--skip-dependencies_ is specified, the process is applied recursively to all the cookbooks _COOKBOOK_ depends on (via metadata _dependencies_). ## DOWNLOAD __knife cookbook site download COOKBOOK [VERSION]__ _(options)_ * `-f`, `--file FILE`: The filename to write to * `--force`: Force download deprecated cookbook Downloads a specific cookbook from the Community site, optionally specifying a certain version. ## LIST __knife cookbook site list__ _(options)_ * `-w`, `--with-uri`: Show corresponding URIs Lists available cookbooks from the Community site. ## SEARCH __knife cookbook site search QUERY__ _(options)_ Searches for available cookbooks matching the specified query. ## SHARE __knife cookbook site share COOKBOOK CATEGORY__ _(options)_ * `-k`, `--key KEY`: API Client Key * `-u`, `--user USER`: API Client Username * `-o`, `--cookbook-path PATH:PATH`: A colon-separated path to look for cookbooks in Uploads the specified cookbook using the given category to the Opscode cookbooks site. Requires a login user and certificate for the Opscode Cookbooks site. By default, knife will use the username and API key you've configured in your configuration file; otherwise you must explicitly set these values on the command line or use an alternate configuration file. ## UNSHARE __knife cookbook site unshare COOKBOOK__ Stops sharing the specified cookbook on the Opscode cookbooks site. ## SHOW __knife cookbook site show COOKBOOK [VERSION]__ _(options)_ Shows information from the site about a particular cookbook. ## DESCRIPTION The cookbook site, , is a cookbook distribution service operated by Opscode. This service provides users with a central location to publish cookbooks for sharing with other community members. `knife cookbook site` commands provide an interface to the cookbook site's HTTP API. For commands that read data from the API, no account is required. In order to upload cookbooks using the `knife cookbook site share` command, you must create an account on the cookbook site and configure your credentials via command line option or in your knife configuration file. ## EXAMPLES Uploading cookbooks to the Opscode cookbooks site: knife cookbook site share example Other -k ~/.chef/USERNAME.pem -u USERNAME ## SEE ALSO __knife-cookbook(1)__ ## AUTHOR Chef was written by Adam Jacob with many contributions from the community. ## DOCUMENTATION This manual page was written by Joshua Timberman . Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. ## CHEF Knife is distributed with Chef. chef-11.8.2/distro/common/markdown/man1/knife-environment.mkd0000644000004100000410000001253012254362222024146 0ustar www-datawww-dataknife-environment(1) -- Define cookbook policies for the environments in your infrastructure ======================================== ## SYNOPSIS __knife__ __environment__ _sub-command_ _(options)_ ## SUBCOMMANDS Environment subcommands follow a basic create, read, update, delete (CRUD) pattern. The following subcommands are available: ## CREATE __knife environment create__ _environment_ _(options)_ * `-d`, `--description DESCRIPTION`: The value of the description field. Create a new environment object on the Chef Server. The envrionment will be opened in the text editor for editing prior to creation if the -n option is not present. ## DELETE __knife environment delete__ _environment_ _(options)_ Destroy an environment on the Chef Server. A prompt for confirmation will be displayed if the -y options is not given. ## EDIT __knife environment edit__ _environment_ _(options)_ Fetch _environment_ and display it in the text editor for editing. The environment will be saved to the Chef Server when the editing session exits. ## FROM FILE __knife environment from file__ _file_ _(options)_ Create or update an environment from the JSON or Ruby format _file_. See __format__ for the proper format of this file. ## LIST __knife environment list__ _(options)_ * `-w`, `--with-uri`: Show the resource URI for each environment ## SHOW __knife environment show__ _environment_ _(options)_ ## DESCRIPTION Environments provide a means to apply policies to hosts in your infrastructure based on business function. For example, you may have a separate copy of your infrastructure called "dev" that runs the latest version of your application and should use the newest versions of your cookbooks when configuring systems, and a production instance of your infrastructure where you wish to update code and cookbooks in a more controlled fashion. In Chef, this function is implemented with _environments_. Environments contain two major components: a set of cookbook version constraints and environment attributes. ## SYNTAX A cookbook version constraint is comprised of a _cookbook name_ and a _version constraint_. The _cookbook name_ is the name of a cookbook in your system, and the _version constraint_ is a String describing the version(s) of that cookbook allowed in the environment. Only one _version constraint_ is supported for a given _cookbook name_. The exact syntax used to define a cookbook version constraint varies depending on whether you use the JSON format or the Ruby format. In the JSON format, the cookbook version constraints for an environment are represented as a single JSON object, like this: {"apache2": ">= 1.5.0"} In the Ruby format, the cookbook version contraints for an environment are represented as a Ruby Hash, like this: {"apache2" => ">= 1.5.0"} A _version number_ is a String comprised of two or three digits separated by a dot (.) character, or in other words, strings of the form "major.minor" or "major.minor.patch". "1.2" and "1.2.3" are examples of valid version numbers. Version numbers containing more than three digits or alphabetic characters are not supported. A _version constraint_ String is composed of an _operator_ and a _version number_. The following operators are available: * `= VERSION`: Equality. Only the exact version specified may be used. * `> VERSION`: Greater than. Only versions greater than `VERSION` may be used. * `>= VERSION`: Greater than or equal to. Only versions equal to VERSION or greater may be used. * `< VERSION`: Less than. Only versions less than VERSION may be used. * `<= VERSION`: Less than or equal to. Only versions lesser or equal to VERSION may be used. * `~> VERSION`: Pessimistic greater than. Depending on the number of components in the given VERSION, the constraint will be optimistic about future minor or patch revisions only. For example, `~> 1.1` will match any version less than `2.0` and greater than or equal to `1.1.0`, whereas `~> 2.0.5` will match any version less than `2.1.0` and greater than or equal to `2.0.5`. ## FORMAT The JSON format of an envioronment is as follows: { "name": "dev", "description": "The development environment", "cookbook_versions": { "couchdb": "= 11.0.0" }, "json_class": "Chef::Environment", "chef_type": "environment", "default_attributes": { "apache2": { "listen_ports": [ "80", "443" ] } }, "override_attributes": { "aws_s3_bucket": "production" } } The Ruby format of an environment is as follows: name "dev" description "The development environment" cookbook_versions "couchdb" => "= 11.0.0" default_attributes "apache2" => { "listen_ports" => [ "80", "443" ] } override_attributes "aws_s3_bucket" => "production" ## SEE ALSO __knife-node(1)__ __knife-cookbook(1)__ __knife-role(1)__ ## AUTHOR Chef was written by Adam Jacob with many contributions from the community. ## DOCUMENTATION This manual page was written by Daniel DeLeo . Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. ## CHEF Knife is distributed with Chef. chef-11.8.2/distro/common/markdown/man1/knife.mkd0000644000004100000410000001734712254362222021617 0ustar www-datawww-dataknife(1) -- Chef Server API client utility ======================================== ## SYNOPSIS __knife__ _sub-command_ [_argument_...] _(options)_ ## DESCRIPTION Knife is a command-line utility used to manage data on a Chef server through the HTTP(S) API. Knife is organized into groups of subcommands centered around the various object types in Chef. Each category of subcommand is documented in its own manual page. Available topics are: * bootstrap * client * configure * cookbook-site * cookbook * data-bag * environment * exec * index * node * recipe * role * search * ssh * status * tag If the knife manuals are in your `MANPATH`, you can access help for the above topics using `man knife-TOPIC`; otherwise, you can view the documentation using `knife help TOPIC`. ## OPTIONS * `-s`, `--server-url` URL: Chef Server URL, corresponds to `Chef::Config` `chef_server_url`. * `-k`, `--key` KEY: API Client Key, corresponds to `Chef::Config` `client_key`. * `-c`, `--config` CONFIG: The configuration file to use * `-E`, `--environment ENVIRONMENT`: Set the Chef environment * `-e`, `--editor` EDITOR: Set the editor to use for interactive commands * `-F`, `--format` FORMAT: Which format to use for output. See FORMATS for details. * `-d`, `--disable-editing`: Do not open EDITOR, just accept the data as is * `-u`, `--user` USER: API Client Username, corresponds to `Chef::Config` `node_name`. * `-p`, `--print-after`: Show the data after a destructive operation * `-v`, `--version`: Show chef version * `-V`, `--verbose`: More verbose output. Use twice for max verbosity. * `-y`, `--yes`: Say yes to all prompts for confirmation * `--defaults`: Accept default values for all questions * `--[no-]color`: Use colored output. Color enabled by default. * `-h`, `--help`: Show the available options for a command. ## SUB-COMMANDS Sub-commands that operate on the basic Chef data types are structured as _NOUN verb NOUN (options)_. For all data types, the following commands are available: * create (create) * list and show (read) * edit (update) * delete (destroy) Knife also includes commands that take actions other than displaying or modifying data on the Chef Server, such as __knife-ssh(1)__. ## CONFIGURATION The knife configuration file is a Ruby DSL to set configuration parameters for Knife's __GENERAL OPTIONS__. The default location for the config file is `~/.chef/knife.rb`. If managing multiple Chef repositories, per-repository config files can be created. The file must be `.chef/knife.rb` in the current directory of the repository. If the config file exists, knife uses these settings for __GENERAL OPTIONS__ defaults. * `node_name`: User or client identity (i.e., _name_) to use for authenticating requests to the Chef Server. * `client_key`: Private key file to authenticate to the Chef server. Corresponds to the `-k` or `--key` option. * `chef_server_url`: URL of the Chef server. Corresponds to the `-s` or `--server-url` option. This is requested from the user when running this sub-command. * `syntax_check_cache_path`: Specifies the path to a directory where knife caches information about files that it has syntax checked. * `validation_client_name`: Specifies the name of the client used to validate new clients. * `validation_key`: Specifies the private key file to use when bootstrapping new hosts. See knife-client(1) for more information about the validation client. * `cookbook_copyright`, `cookbook_email`, `cookbook_license`, `readme_format` Used by `knife cookbook create` sub-command to specify the copyright holder, maintainer email, license and readme format (respectively) for new cookbooks. The copyright holder is listed as the maintainer in the cookbook's metadata and as the Copyright in the comments of the default recipe. The maintainer email is used in the cookbook metadata. The license determines what preamble to put in the comment of the default recipe, and is listed as the license in the cookbook metadata. Currently supported licenses are "apachev2" and "none". Any other values will result in an empty license in the metadata (needs to be filled in by the author), and no comment preamble in the default recipe. Currently supported readme formats are "md", "mkd", "txt", and "rdoc". Any other value will result in an unformatted README. ## FILES _~/.chef/knife.rb_ Ruby DSL configuration file for knife. See __CONFIGURATION__. ## FORMATS The amount of content displayed and the output format are modified by the `--format` option. If no alternate format is selected, the default is summary. Valid formats are: * `summary`: displays the node in a custom, summarized format (default) * `text`: displays the node data in its entirety using the colorized tree display * `json`: displays the node in JSON format * `yaml`: displays the node in YAML format * `pp`: displays the node using Ruby's pretty printer. For brevity, only the first character of the format is required, for example, -Fj will produce JSON format output. ## CHEF WORKFLOW When working with Chef and Knife in the local repository, the recommended workflow outline looks like: * Create repository. A skeleton sample is provided at _http://github.com/opscode/chef-repo/_. * Configure knife, see __CONFIGURATION__. * Download cookbooks from the Opscode cookbooks site, see __COOKBOOK SITE SUB-COMMANDS__. * Or, create new cookbooks, see `cookbook create` sub-command. * Commit changes to the version control system. See your tool's documentation. * Upload cookbooks to the Chef Server, see __COOKBOOK SUB-COMMANDS__. * Launch instances in the Cloud, OR provision new hosts; see __CLOUD COMPUTING SUB-COMMANDS__ and __BOOTSTRAP SUB-COMMANDS__. * Watch Chef configure systems! A note about git: Opscode and many folks in the Chef community use git, but it is not required, except in the case of the `cookbook site vendor` sub-command, as it uses git directly. Version control is strongly recommended though, and git fits with a lot of the workflow paradigms. ## EXAMPLES ## ENVIRONMENT * `EDITOR`: The text editor to use for editing data. The --editor option takes precedence over this value, and the --disable-editing option supresses data editing entirely. ## SEE ALSO __chef-client(8)__ __chef-server(8)__ __chef-shell(1)__ __knife-bootstrap(1)__ __knife-client(1)__ __knife-configure(1)__ __knife-cookbook-site(1)__ __knife-cookbook(1)__ __knife-data-bag(1)__ __knife-environment(1)__ __knife-exec(1)__ __knife-index(1)__ __knife-node(1)__ __knife-recipe(1)__ __knife-role(1)__ __knife-search(1)__ __knife-ssh(1)__ __knife-tag(1)__ Complete Chef documentation is available online: JSON is JavaScript Object Notation SOLR is an open source search engine. __git(1)__ is a version control system This manual page was generated from Markdown with __ronn(1)__ ## AUTHOR Chef was written by Adam Jacob of Opscode (), with contributions from the community. ## DOCUMENTATION This manual page was written by Joshua Timberman . ## LICENSE Both Chef and this documentation are released under the terms of the Apache 2.0 License. You may view the license online: On some systems, the complete text of the Apache 2.0 License may be found in `/usr/share/common-licenses/Apache-2.0`. ## CHEF Knife is distributed with Chef. chef-11.8.2/distro/common/markdown/man1/knife-search.mkd0000644000004100000410000001237712254362222023060 0ustar www-datawww-dataknife-search(1) -- Find objects on a Chef Server by query ======================================== ## SYNOPSIS __knife__ __search INDEX QUERY__ _(options)_ * `-a`, `--attribute ATTR`: Show only one attribute * `-i`, `--id-only`: Show only the ID of matching objects * `-q`, `--query QUERY`: The search query; useful to protect queries starting with - * `-R`, `--rows INT`: The number of rows to return * `-r`, `--run-list`: Show only the run list * `-o`, `--sort SORT`: The order to sort the results in * `-b`, `--start ROW`: The row to start returning results at * `-m`, `--medium`: Display medium sized output when searching nodes using the default summary format * `-l`, `--long`: Display long output when searching nodes using the default summary format ## DESCRIPTION Search is a feature of the Chef Server that allows you to use a full-text search engine to query information about your infrastructure and applications. You can utilize this service via search calls in a recipe or the knife search command. The search syntax is based on Lucene. ## INDEXES Search indexes are a feature of the Chef Server and the search sub-command allows querying any of the available indexes using SOLR query syntax. The following data types are indexed for search: * _node_ * _role_ * _environment_ * _clients_ * _data bag_ Data bags are indexed by the data bag's name. For example, to search a data bag named "admins": knife search admins "field:search_pattern" ## QUERY SYNTAX Queries have the form `field:search_pattern` where `field` is a key in the JSON description of the relevant objects (nodes, roles, environments, or data bags). Both `field` and `search_pattern` are case-sensitive. `search_pattern` can be an exact, wildcard, range, or fuzzy match (see below). The `field` supports exact matching and limited wildcard matching. Searches will return the relevant objects (nodes, roles, environments, or data bags) where the `search_pattern` matches the object's value of `field`. ### FIELD NAMES Field names are the keys within the JSON description of the object being searched. Nested Keys can be searched by placing an underscore ("_") between key names. ### WILDCARD MATCHING FOR FIELD NAMES The field name also has limited support for wildcard matching. Both the "*" and "?" wildcards (see below) can be used within a field name; however, they cannot be the first character of the field name. ### EXACT MATCHES Without any search modifiers, a search returns those fields for which the `search_pattern` exactly matches the value of `field` in the JSON description of the object. ### WILDCARD MATCHES Search support both single- and multi-character wildcard searches within a search pattern. '?' matches exactly one character. '*' matches zero or more characters. ### RANGE MATCHES Range searches allows one to match values between two given values. To match values between X and Y, inclusively, use square brackets: knife search INDEX 'field:[X TO Y] To match values between X and Y, exclusively, use curly brackets: knife search INDEX 'field:{X TO Y}' Values are sorted in lexicographic order. ### FUZZY MATCHES Fuzzy searches allows one to match values based on the Levenshtein Distance algorithm. To perform a fuzzy match, append a tilda (~) to the search term: knife search INDEX 'field:term~' This search would return nodes whose `field` was 'perm' or 'germ'. ### BOOLEAN OPERATORS The boolean operators NOT, AND, and OR are supported. To find values of `field` that are not X: knife search INDEX 'field:(NOT X)' To find records where `field1` is X and `field2` is Y: knife search INDEX 'field1:X AND field2:Y' To find records where `field` is X or Y: knife search INDEX 'field:X OR field:Y' ### QUOTING AND SPECIAL CHARACTERS In order to avoid having special characters and escape sequences within your search term interpreted by either Ruby or the shell, enclose them in single quotes. Search terms that include spaces should be enclosed in double-quotes: knife search INDEX 'field:"term with spaces"' The following characters must be escaped: + - && || ! ( ) { } [ ] ^ " ~ * ? : \ ## EXAMPLES Find the nodes with the fully-qualified domain name (FQDN) www.example.com: knife search node 'fqdn:www.example.com' Find the nodes running a version of Ubuntu: knife search node 'platform:ubuntu*' Find all nodes running CentOS in the production environment: knife search node 'chef_environment:production AND platform:centos' ## KNOWN BUGS * Searches against the client index return no results in most cases. (CHEF-2477) * Searches using the fuzzy match operator (~) produce an error. (CHEF-2478) ## SEE ALSO __knife-ssh__(1) [Lucene Query Parser Syntax](http://lucene.apache.org/java/2_3_2/queryparsersyntax.html) ## AUTHOR Chef was written by Adam Jacob with many contributions from the community. ## DOCUMENTATION This manual page was written by Joshua Timberman . Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. ## CHEF Knife is distributed with Chef. chef-11.8.2/distro/common/markdown/man1/knife-configure.mkd0000644000004100000410000000533112254362222023564 0ustar www-datawww-dataknife-configure(1) -- Generate configuration files for knife or Chef Client ======================================== ## SYNOPSIS __knife__ __configure__ [client] _(options)_ ## DESCRIPTION Generates a knife.rb configuration file interactively. When given the --initial option, also creates a new administrative user. ## CONFIGURE SUBCOMMANDS ## __knife configure__ _(options)_ * `-i`, `--initial`: Create an initial API Client * `-r`, `--repository REPO`: The path to your chef-repo Create a configuration file for knife. This will prompt for values to enter into the file. Default values are listed in square brackets if no other entry is typed. See __knife__(1) for a description of configuration options. __knife configure client__ _directory_ Read the _knife.rb_ config file and generate a config file suitable for use in _/etc/chef/client.rb_ and copy the validation certificate into the specified _directory_. ## EXAMPLES * On a freshly installed Chef Server, use _knife configure -i_ to create an administrator and knife configuration file. Leave the field blank to accept the default value. On most systems, the default values are acceptable. user@host$ knife configure -i Please enter the chef server URL: [http://localhost:4000] Please enter a clientname for the new client: [username] Please enter the existing admin clientname: [chef-webui] Please enter the location of the existing admin client's private key: [/etc/chef/webui.pem] Please enter the validation clientname: [chef-validator] Please enter the location of the validation key: [/etc/chef/validation.pem] Please enter the path to a chef repository (or leave blank): Creating initial API user... Created (or updated) client[username] Configuration file written to /home/username/.chef/knife.rb This creates a new administrator client named _username_, writes a configuration file to _/home/username/.chef/knife.rb_, and the private key to _/home/username/.chef/username.pem_. The configuration file and private key may be copied to another system to facilitate administration of the Chef Server from a remote system. Depending on the value given for the Chef Server URL, you may need to modify that setting after copying to a remote host. ## SEE ALSO __knife__(1) __knife-client__(1) ## AUTHOR Chef was written by Adam Jacob with many contributions from the community. ## DOCUMENTATION This manual page was written by Joshua Timberman . Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. ## CHEF Knife is distributed with Chef. chef-11.8.2/distro/common/markdown/man1/knife-client.mkd0000644000004100000410000000634712254362222023071 0ustar www-datawww-dataknife-client(1) -- Manage Chef API Clients ======================================== ## SYNOPSIS __knife__ __client__ _sub-command_ _(options)_ ## SUB-COMMANDS Client subcommands follow a basic create, read, update, delete (CRUD) pattern. The Following subcommands are available: ## BULK DELETE __knife client bulk delete__ _regex_ _(options)_ Delete clients where the client name matches the regular expression _regex_ on the Chef Server. The regular expression should be given as a quoted string, and not surrounded by forward slashes. ## CREATE __knife client create__ _client name_ _(options)_ * `-a`, `--admin `: Create the client as an admin * `-f`, `--file FILE`: Write the key to a file Create a new client. This generates an RSA keypair. The private key will be displayed on _STDOUT_ or written to the named file. The public half will be stored on the Server. For _chef-client_ systems, the private key should be copied to the system as `/etc/chef/client.pem`. Admin clients should be created for users that will use _knife_ to access the API as an administrator. The private key will generally be copied to `~/.chef/client\_name.pem` and referenced in the `knife.rb` configuration file. ## DELETE __knife client delete__ _client name_ _(options)_ Deletes a registered client. ## EDIT __client edit__ _client name_ _(options)_ Edit a registered client. ## LIST __client list__ _(options)_ * `-w`, `--with-uri`: Show corresponding URIs List all registered clients. ## REREGISTER __client reregister__ _client name_ _(options)_ * `-f`, `--file FILE`: Write the key to a file Regenerate the RSA keypair for a client. The public half will be stored on the server and the private key displayed on _STDOUT_ or written to the named file. This operation will invalidate the previous keypair used by the client, preventing it from authenticating with the Chef Server. Use care when reregistering the validator client. ## SHOW __client show__ _client name_ _(options)_ * `-a`, `--attribute ATTR`: Show only one attribute Show a client. Output format is determined by the --format option. ## DESCRIPTION Clients are identities used for communication with the Chef Server API, roughly equivalent to user accounts on the Chef Server, except that clients only communicate with the Chef Server API and are authenticated via request signatures. In the typical case, there will be one client object on the server for each node, and the corresponding client and node will have identical names. In the Chef authorization model, there is one special client, the "validator", which is authorized to create new non-administrative clients but has minimal privileges otherwise. This identity is used as a sort of "guest account" to create a client identity when initially setting up a host for management with Chef. ## SEE ALSO __knife-node__(1) ## AUTHOR Chef was written by Adam Jacob with many contributions from the community. ## DOCUMENTATION This manual page was written by Joshua Timberman . Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. ## CHEF Knife is distributed with Chef. chef-11.8.2/distro/common/markdown/man1/knife-cookbook.mkd0000644000004100000410000002313512254362222023413 0ustar www-datawww-dataknife-cookbook(1) -- upload and manage chef cookbooks ======================================== ## SYNOPSIS __knife__ __cookbook__ _sub-command_ _(options)_ ## SUB-COMMANDS `knife cookbook` supports the following sub commands: ## LIST __knife cookbook list__ _(options)_ * `-a`, `--all`: show all versions of a cookbook instead of just the most recent * `-w`, `--with-uri`: show corresponding uris Lists the cookbooks available on the Chef server. ## SHOW __knife cookbook show cookbook [version] [part] [filename]__ _(options)_ * `-f`, `--fqdn fqdn `: the fqdn of the host to see the file for * `-p`, `--platform platform `: the platform to see the file for * `-v`, `--platform-version version`: the platform version to see the file for * `-w`, `--with-uri`: Show corresponding URIs show a particular part of a _cookbook_ for the specified _version_. _part_ can be one of: * _attributes_ * _definitions_ * _files_ * _libraries_ * _providers_ * _recipes_ * _resources_ * _templates_ ## UPLOAD __knife cookbook upload [cookbooks...]__ _(options)_ * `-a`, `--all`: upload all cookbooks, rather than just a single cookbook * `-o`, `--cookbook-path path:path`: a colon-separated path to look for cookbooks in * `-d`, `--upload-dependencies`: Uploads additional cookbooks that this cookbook lists in as dependencies in its metadata. * `-E`, `--environment ENVIRONMENT`: An _ENVIRONMENT_ to apply the uploaded cookbooks to. Specifying this option will cause knife to edit the _ENVIRONMENT_ to place a strict version constraint on the cookbook version(s) uploaded. * `--freeze`: Sets the frozen flag on the uploaded cookbook(s) Any future attempt to modify the cookbook without changing the version number will return an error unless --force is specified. * `--force`: Overrides the frozen flag on a cookbook, allowing you to overwrite a cookbook version that has previously been uploaded with the --freeze option. Uploads one or more cookbooks from your local cookbook repository(ies) to the Chef Server. Only files that don't yet exist on the server will be uploaded. As the command parses the name args as 1..n cookbook names: `knife cookbook upload COOKBOOK COOKBOOK ...` works for one to many cookbooks. ## DOWNLOAD __knife cookbook download cookbook [version]__ _(options)_ * `-d`, `--dir download_directory`: the directory to download the cookbook into * `-f`, `--force`: overwrite an existing directory with the download * `-n`, `--latest`: download the latest version of the cookbook download a cookbook from the chef server. if no version is specified and only one version exists on the server, that version will be downloaded. if no version is specified and multiple versions are available on the server, you will be prompted for a version to download. ## DELETE __knife cookbook delete cookbook [version]__ _(options)_ * `-a`, `--all`: delete all versions * `-p`, `--purge`: purge files from backing store. this will disable any cookbook that contains any of the same files as the cookbook being purged. delete the specified _version_ of the named _cookbook_. if no version is specified, and only one version exists on the server, that version will be deleted. if multiple versions are available on the server, you will be prompted for a version to delete. ## BULK DELETE __knife cookbook bulk delete regex__ _(options)_ * `-p`, `--purge`: purge files from backing store. this will disable any cookbook that contains any of the same files as the cookbook being purged. delete cookbooks on the chef server based on a regular expression. the regular expression (_regex_) should be in quotes, not in //'s. ## COOKBOOK CREATE __knife cookbook create cookbook__ _(options)_ * `-o`, `--cookbook-path path`: the directory where the cookbook will be created * `-r`, `--readme-format format`: format of the readme file md, mkd, txt, rdoc * `-C`, `--copyright copyright`: name of copyright holder * `-i`, `--license license`: license for cookbook, apachev2 or none * `-m`, `--email email`: email address of cookbook maintainer this is a helper command that creates a new cookbook directory in the `cookbook_path`. the following directories and files are created for the named cookbook. * cookbook/attributes * cookbook/definitions * cookbook/files/default * cookbook/libraries * cookbook/metadata.rb * cookbook/providers * cookbook/readme.md * cookbook/recipes/default.rb * cookbook/resources * cookbook/templates/default supported readme formats are 'md' (default), 'mkd', 'txt', 'rdoc'. the readme file will be written with the specified extension and a set of helpful starting headers. specify `-C` or `--copyright` with the name of the copyright holder as your name or your company/organization name in a quoted string. if this value is not specified an all-caps string `your_company_name` is used which can be easily changed with find/replace. specify `-i` or `--license` with the license that the cookbook is distributed under for sharing with other people or posting to the opscode cookbooks site. be aware of the licenses of files you put inside the cookbook and follow any restrictions they describe. when using `none` (default) or `apachev2`, comment header text and metadata file are pre-filled. the `none` license will be treated as non-redistributable. specify `-m` or `--email` with the email address of the cookbook's maintainer. if this value is not specified, an all-caps string `your_email` is used which can easily be changed with find/replace. the cookbook copyright, license, email and readme_format settings can be filled in the `knife.rb`, for example with default values: cookbook_copyright "your_company_name" cookbook_license "none" cookbook_email "your_email" readme_format "md" ## METADATA __knife cookbook metadata cookbook__ _(options)_ * `-a`, `--all`: generate metadata for all cookbooks, rather than just a single cookbook * `-o`, `--cookbook-path path:path`: a colon-separated path to look for cookbooks in generate cookbook metadata for the named _cookbook_. the _path_ used here specifies where the cookbooks directory is located and corresponds to the `cookbook_path` configuration option. ## METADATA FROM FILE __knife cookbook metadata from file__ _(options)_ load the cookbook metadata from a specified file. ## TEST __knife cookbook test [cookbooks...]__ _(options)_ * `-a`, `--all`: test all cookbooks, rather than just a single cookbook * `-o`, `--cookbook-path path:path`: a colon-separated path to look for cookbooks in test the specified cookbooks for syntax errors. this uses the built-in ruby syntax checking option for files in the cookbook ending in `.rb`, and the erb syntax check for files ending in `.erb` (templates). ## RECIPE LIST __knife recipe list [PATTERN]__ List available recipes from the server. Specify _PATTERN_ as a regular expression to limit the results. ## DESCRIPTION Cookbooks are the fundamental unit of distribution in Chef. They encapsulate all recipes of resources and assets used to configure a particular aspect of the infrastructure. The following sub-commands can be used to manipulate the cookbooks stored on the Chef Server. On disk, cookbooks are directories with a defined structure. The following directories may appear within a cookbook: * COOKBOOK/attributes/: Ruby files that define default parameters to be used in recipes * COOKBOOK/definitions/: Ruby files that contain _resource definitions_ * COOKBOOK/files/SPECIFICITY: Files of arbitrary type. These files may be downloaded by chef-client(8) when configuring a host. * COOKBOOK/libraries/: Ruby files that contain library code needed for recipes * COOKBOOK/providers/: Ruby files that contain Lightweight Provider definitions * COOKBOOK/recipes/: Ruby files that use Chef's recipe DSL to describe the desired configuration of a system * COOKBOOK/resources/: Ruby files that contain Lightweight Resource definitions * COOKBOOK/templates/SPECIFICITY: ERuby (ERb) template files. These are referenced by _recipes_ and evaluated to dynamically generate configuration files. __SPECIFICITY__ is a feature of _files_ and _templates_ that allow you to specify alternate files to be used on a specific OS platform or host. The default specificity setting is _default_, that is files in `COOKBOOK/files/default` will be used when a more specific copy is not available. Further documentation for this feature is available on the Chef wiki: Cookbooks also contain a metadata file that defines various properties of the cookbook. The most important of these are the _version_ and the _dependencies_. The _version_ is used in combination with environments to select which copy of a given cookbook is distributed to a node. The _dependencies_ are used by the server to determine which additional cookbooks must be distributed to a given host when it requires a cookbook. ## SEE ALSO __knife-environment(1)__ __knife-cookbook-site(1)__ ## AUTHOR Chef was written by Adam Jacob with many contributions from the community. ## DOCUMENTATION This manual page was written by Joshua Timberman . Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. ## CHEF Knife is distributed with Chef. chef-11.8.2/distro/common/markdown/man1/chef-shell.mkd0000644000004100000410000001471712254362222022533 0ustar www-datawww-datachef-shell(1) -- Interactive Chef Console ========================================= ## SYNOPSIS __chef-shell__ [_named configuration_] _(options)_ * `-S`, `--server CHEF_SERVER_URL`: The chef server URL * `-z`, `--client`: chef-client mode * `-c`, `--config CONFIG`: The configuration file to use * `-j`, `--json-attributes JSON_ATTRIBS`: Load attributes from a JSON file or URL * `-l`, `--log-level LOG_LEVEL`: Set the logging level * `-s`, `--solo`: chef-solo session * `-a`, `--standalone`: standalone session * `-v`, `--version`: Show chef version * `-h`, `--help`: Show command options When no --config option is specified, chef-shell attempts to load a default configuration file: * If a _named configuration_ is given, chef-shell will load ~/.chef/_named configuration_/chef_shell.rb * If no _named configuration_ is given chef-shell will load ~/.chef/chef_shell.rb if it exists * chef-shell falls back to loading /etc/chef/client.rb or /etc/chef/solo.rb if -z or -s options are given and no chef_shell.rb can be found. * The --config option takes precedence over implicit configuration paths. ## DESCRIPTION `chef-shell` is an irb(1) (interactive ruby) session customized for Chef. `chef-shell` serves two primary functions: it provides a means to interact with a Chef Server interactively using a convenient DSL; it allows you to define and run Chef recipes interactively. ## SYNTAX chef-shell uses irb's subsession feature to provide multiple modes of interaction. In addition to the primary mode which is entered on start, `recipe` and `attributes` modes are available. ## PRIMARY MODE The following commands are available in the primary session: * `help`: Prints a list of available commands * `version`: Prints the Chef version * `recipe`: Switches to `recipe` mode * `attributes`: Switches to `attributes` mode * `run_chef`: Initiates a chef run * `reset`: reinitializes chef-shell session * `echo :on|:off`: Turns irb's echo function on or off. Echo is _on_ by default. * `tracing :on|:off`: Turns irb's function tracing feature on or off. Tracing is extremely verbose and expected to be of interest primarily to developers. * `node`: Returns the _node_ object for the current host. See knife-node(1) for more information about nodes. * `ohai`: Prints the attributes of _node_ In addition to these commands, chef-shell provides a DSL for accessing data on the Chef Server. When working with remote data in chef-shell, you chain method calls in the form _object type_._operation_, where _object type_ is in plural form. The following object types are available: * `nodes` * `roles` * `data_bags` * `clients` * `cookbooks` For each _object type_ the following operations are available: * _object type_.all(_&block_): Loads all items from the server. If the optional code _block_ is given, each item will be passed to the block and the results returned, similar to ruby's `Enumerable#map` method. * _object type_.show(_object name_): Aliased as _object type_.load Loads the singular item identified by _object name_. * _object type_.search(_query_, _&block_): Aliased as _object type_.find Runs a search against the server and returns the matching items. If the optional code _block_ is given each item will be passed to the block and the results returned. The _query_ may be a Solr/Lucene format query given as a String, or a Hash of conditions. If a Hash is given, the options will be ANDed together. To join conditions with OR, use negative queries, or any advanced search syntax, you must provide give the query in String form. * _object type_.transform(:all|_query_, _&block_): Aliased as _object type_.bulk_edit Bulk edit objects by processing them with the (required) code _block_. You can edit all objects of the given type by passing the Symbol `:all` as the argument, or only a subset by passing a _query_ as the argument. The _query_ is evaluated in the same way as with __search__. The return value of the code _block_ is used to alter the behavior of `transform`. If the value returned from the block is `nil` or `false`, the object will not be saved. Otherwise, the object is saved after being passed to the block. This behavior can be exploited to create a dry run to test a data transformation. ## RECIPE MODE Recipe mode implements Chef's recipe DSL. Exhaustively documenting this DSL is outside the scope of this document. See the following pages in the Chef documentation for more information: * * Once you have defined resources in the recipe, you can trigger a convergence run via `run_chef` ## EXAMPLES * A "Hello World" interactive recipe chef > recipe chef:recipe > echo :off chef:recipe > file "/tmp/hello\_world" chef:recipe > run\_chef [Sat, 09 Apr 2011 08:56:56 -0700] INFO: Processing file[/tmp/hello\_world] action create ((irb#1) line 2) [Sat, 09 Apr 2011 08:56:56 -0700] INFO: file[/tmp/hello\_world] created file /tmp/hello\_world chef:recipe > pp ls '/tmp' [".", "..", "hello\_world"] * Search for _nodes_ by role, and print their IP addresses chef > nodes.find(:roles => 'monitoring-server') {|n| n[:ipaddress] } => ["10.254.199.5"] * Remove the role _obsolete_ from every node in the system chef > nodes.transform(:all) {|n| n.run\_list.delete('role[obsolete]') } => [node[chef098b2.opschef.com], node[ree-woot], node[graphite-dev], node[fluke.localdomain], node[ghost.local], node[kallistec]] ## BUGS `chef-shell` often does not perfectly replicate the context in which chef-client(8) configures a host, which may lead to discrepancies in observed behavior. `chef-shell` has to duplicate much code from chef-client's internal libraries and may become out of sync with the behavior of those libraries. ## SEE ALSO chef-client(8) knife(1) ## AUTHOR Chef was written by Adam Jacob with many contributions from the community. chef-shell was written by Daniel DeLeo. ## DOCUMENTATION This manual page was written by Daniel DeLeo . Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. ## CHEF chef-shell is distributed with Chef. chef-11.8.2/distro/common/markdown/man1/knife-bootstrap.mkd0000644000004100000410000001255312254362222023624 0ustar www-datawww-dataknife-bootstrap(1) -- Install Chef Client on a remote host ======================================== ## SYNOPSIS __knife__ __bootstrap__ _(options)_ * `-i`, `--identity-file IDENTITY_FILE`: The SSH identity file used for authentication * `-N`, `--node-name NAME`: The Chef node name for your new node * `-P`, `--ssh-password PASSWORD`: The ssh password * `-x`, `--ssh-user USERNAME`: The ssh username * `-p`, `--ssh-port PORT`: The ssh port * `--bootstrap-version VERSION`: The version of Chef to install * `--bootstrap-proxy PROXY_URL`: `The proxy server for the node being bootstrapped` * `--prerelease`: Install pre-release Chef gems * `-r`, `--run-list RUN_LIST`: Comma separated list of roles/recipes to apply * `--template-file TEMPLATE`: Full path to location of template to use * `--sudo`: Execute the bootstrap via sudo * `-d`, `--distro DISTRO`: Bootstrap a distro using a template * `--[no-]host-key-verify`: Enable host key verification, which is the default behavior. * `--hint HINT_NAME[=HINT_FILE]`: Provide the name of a hint (with option JSON file) to set for use by Ohai plugins. ## DESCRIPTION Performs a Chef Bootstrap on the target node. The goal of the bootstrap is to get Chef installed on the target system so it can run Chef Client with a Chef Server. The main assumption is a baseline OS installation exists. This sub-command is used internally by some cloud computing plugins. The bootstrap sub-command supports supplying a template to perform the bootstrap steps. If the distro is not specified (via `-d` or `--distro` option), an Ubuntu 10.04 host bootstrapped with RubyGems is assumed. The __DISTRO__ value corresponds to the base filename of the template, in other words `DISTRO`.erb. A template file can be specified with the `--template-file` option in which case the __DISTRO__ is not used. The sub-command looks in the following locations for the template to use: * `bootstrap` directory in the installed Chef Knife library. * `bootstrap` directory in the `$PWD/.chef`. * `bootstrap` directory in the users `$HOME/.chef`. The default bootstrap templates are scripts that get copied to the target node (FQDN). The following distros are supported: * centos5-gems * fedora13-gems * ubuntu10.04-gems * ubuntu10.04-apt The gems installations will use RubyGems 1.3.6 and Chef installed as a gem. The apt installation will use the Opscode APT repository. In addition to handling the software installation, these bootstrap templates do the following: - Write the validation.pem per the local knife configuration. - Write a default config file for Chef (`/etc/chef/client.rb`) using values from the `knife.rb`. - Create a JSON attributes file containing the specified run list and run Chef. In the case of the RubyGems, the `client.rb` will be written from scratch with a minimal set of values; see __EXAMPLES__. In the case of APT Package installation, `client.rb` will have the `validation_client_name` appended if it is not set to `chef-validator` (default config value), and the `node_name` will be added if `chef_node_name` option is specified. When this is complete, the bootstrapped node will have: - Latest Chef version installed from RubyGems or APT Packages from Opscode. This may be a later version than the local system. - Be validated with the configured Chef Server. - Have run Chef with its default run list if one is specfied. Additional custom bootstrap templates can be created and stored in `.chef/bootstrap/DISTRO.erb`, replacing __DISTRO__ with the value passed with the `-d` or `--distro` option. See __EXAMPLES__ for more information. ## EXAMPLES Setting up a custom bootstrap is fairly straightforward. Create a `.chef/bootstrap` directory in your Chef Repository or in `$HOME/.chef/bootstrap`. Then create the ERB template file. mkdir ~/.chef/bootstrap vi ~/.chef/bootstrap/debian5.0-apt.erb For example, to create a new bootstrap template that should be used when setting up a new Debian node. Edit the template to run the commands, set up the validation certificate and the client configuration file, and finally to run chef-client on completion. The bootstrap template can be called with: knife bootstrap mynode.example.com --template-file ~/.chef/bootstrap/debian5.0-apt.erb Or, knife bootstrap mynode.example.com --distro debian5.0-apt The `--distro` parameter will automatically look in the `~/.chef/bootstrap` directory for a file named `debian5.0-apt.erb`. Templates provided by the Chef installation are located in `BASEDIR/lib/chef/knife/bootstrap/*.erb`, where _BASEDIR_ is the location where the package or Gem installed the Chef client libraries. ## BUGS `knife bootstrap` is not capable of bootstrapping multiple hosts in parallel. The bootstrap script is passed as an argument to sh(1) on the remote system, so sensitive information contained in the script will be visible to other users via the process list using tools such as ps(1). ## SEE ALSO __knife-ssh__(1) ## AUTHOR Chef was written by Adam Jacob with many contributions from the community. ## DOCUMENTATION This manual page was written by Joshua Timberman . Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. ## CHEF Knife is distributed with Chef. chef-11.8.2/distro/common/markdown/man1/knife-index.mkd0000644000004100000410000000176512254362222022721 0ustar www-datawww-dataknife-index(1) -- Rebuild the search index on a Chef Server ======================================== ## SYNOPSIS __knife__ __index rebuild__ _(options)_ * `-y`, `--yes`: don't bother to ask if I'm sure ## DESCRIPTION Rebuilds all the search indexes on the server. This is accomplished by deleting all objects from the search index, and then forwarding each item in the database to __chef-expander__(8) via __rabbitmq-server__(1). Depending on the number of objects in the database, it may take some time for all objects to be indexed and available for search. ## SEE ALSO __knife-search__(1) ## AUTHOR Chef was written by Adam Jacob with many contributions from the community. ## DOCUMENTATION This manual page was written by Joshua Timberman . Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. ## CHEF Knife is distributed with Chef. chef-11.8.2/distro/common/markdown/man1/knife-tag.mkd0000644000004100000410000000160312254362222022354 0ustar www-datawww-dataknife-tag(1) -- Apply tags to nodes on a Chef Server ======================================== ## SYNOPSIS __knife__ __tag__ _subcommand_ _(options)_ ## TAG SUBCOMMANDS The following `tag` subcommands are available: ## CREATE __knife tag create__ _node_ _tag_ [_..._] Adds one or more tags to _node_ ## DELETE __knife tag delete__ _node_ _tag_ [_..._] Removes one or more tags from _node_ ## LIST __knife tag list__ _node_ Lists the tags applied to _node_ ## SEE ALSO __knife-node(1)__ ## AUTHOR Chef was written by Adam Jacob with many contributions from the community. ## DOCUMENTATION This manual page was written by Daniel DeLeo . Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. ## CHEF Knife is distributed with Chef. chef-11.8.2/distro/common/markdown/man1/knife-data-bag.mkd0000644000004100000410000001027512254362222023246 0ustar www-datawww-dataknife-data-bag(1) -- Store arbitrary data on a Chef Server ======================================== ## SYNOPSIS __knife__ __data bag__ _sub-command_ _(options)_ ## DESCRIPTION Data bags are stores of arbitrary JSON data. Each data bag is a collection that may contain many items. Data Bag Items are indexed by the Chef Server and can be searched via __knife-search__(1). Data bags are available to all nodes configured by __chef-client__(8), and are therefore a convenient mechanism to store global information, such as lists of administrative accounts that should be configured on all hosts. ## DATA BAG SUB-COMMANDS ## CREATE __knife data bag create__ _bag name_ [item id] _(options)_ * `-s`, `--secret SECRET`: A secret key used to encrypt the data bag item. See __encryption support__ below. * `--secret-file SECRET_FILE`: The path to a file containing the secret key to be used to encrypt the data bag item. If _item id_ is given, creates a new, empty data bag item and opens it for editing in your editor. The data bag will be created if it does not exist. If _item id_ is not given, the data bag will be created. ## DELETE __knife data bag delete__ _bag name_ [item id] _(options)_ Delete a data bag, or an item from a data bag. ## EDIT __knife data bag edit__ _bag name_ _item id_ _(options)_ * `-s`, `--secret SECRET`: A secret key used to encrypt the data bag item. See __encryption support__ below. * `--secret-file SECRET_FILE`: The path to a file containing the secret key to be used to encrypt the data bag item. Edit an item in a data bag. ## FROM FILE __knife data bag from file__ _bag name_ _file_ _(options)_ __knife data bag from file__ _bag name_ _file1_ _file2_ _file3_ _(options)_ __knife data bag from file__ _bag name_ _folder_ _(options)_ * `-s`, `--secret SECRET`: A secret key used to encrypt the data bag item. See __encryption support__ below. * `--secret-file SECRET_FILE`: The path to a file containing the secret key to be used to encrypt the data bag item. Load a data bag item from a JSON file. If _file_ is a relative or absolute path to the file, that file will be used. Otherwise, the _file_ parameter is treated as the base name of a data bag file in a Chef repository, and `knife` will search for the file in `./data_bags/bag_name/file`. For example `knife data bag from file users dan.json` would attempt to load the file `./data_bags/users/dan.json`. ## LIST __knife data bag list__ _(options)_ * `-w`, `--with-uri`: Show corresponding URIs Lists the data bags that exist on the Chef Server. ## SHOW __knife data bag show BAG [ITEM]__ _(options)_ * `-s`, `--secret SECRET`: A secret key used to encrypt the data bag item. See __encryption support__ below. * `--secret-file SECRET_FILE`: The path to a file containing the secret key to be used to encrypt the data bag item. Show a specific data bag or an item in a data bag. The output will be formatted according to the --format option. ## ENCRYPTION SUPPORT Data Bag Items may be encrypted to keep their contents secret. This may be desireable when storing sensitive information such as database passwords, API keys, etc. Data Bag Item encryption uses the AES-256 CBC symmetric key algorithm. __CAVEATS:__ Keys are not encrypted; only values are encrypted. The "id" of a Data Bag Item is not encrypted, since it is used by Chef Server to store the item in its database. For example, given the following data bag item: {"id": "important_passwords", "secret_password": "opensesame"} The key "secret\_password" will be visible to an evesdropper, but the value "opensesame" will be protected. Both the key "id" and its value "important\_passwords" will be visible to an evesdropper. Chef Server does not provide a secure mechanism for distributing encryption keys. ## SEE ALSO __knife-search__(1) ## AUTHOR Chef was written by Adam Jacob with many contributions from the community. ## DOCUMENTATION This manual page was written by Joshua Timberman . Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. ## CHEF Knife is distributed with Chef. http://wiki.opscode.com/display/chef/Home chef-11.8.2/distro/common/markdown/man1/knife-ssh.mkd0000644000004100000410000000471112254362222022401 0ustar www-datawww-dataknife-ssh(1) -- Run a command or interactive session on multiple remote hosts ======================================== ## SYNOPSIS __knife__ __ssh QUERY COMMAND__ _(options)_ * `-a`, `--attribute ATTR `: The attribute to use for opening the connection - default is fqdn * `-C`, `--concurrency NUM `: The number of concurrent connections * `-m`, `--manual-list `: QUERY is a space separated list of servers * `-P`, `--ssh-password PASSWORD`: The ssh password * `-x`, `--ssh-user USERNAME `: The ssh username * `-i`, `--identity-file IDENTITY_FILE`: The SSH identity file used for authentication * `-p`, `--ssh-port PORT`: The ssh port * `--[no-]host-key-verify`: Verify host key, enabled by default. ## DESCRIPTION The _ssh_ sub-command opens an ssh session to each of the nodes in the search results of the _QUERY_. This sub-command requires that the net-ssh-multi and highline Ruby libraries are installed. On Debian systems, these are the libnet-ssh-multi-ruby and libhighline-ruby packages. They can also be installed as RubyGems (net-ssh-multi and highline, respectively). ## TERMINAL MULTIPLEXING AND TERMINAL TAB SUPPORT `knife ssh` integrates with several terminal multiplexer programs to provide a more convenient means of managing multiple ssh sessions. When the _COMMAND_ option matches one of these, `knife ssh` will create multiple interactive ssh sessions running locally in the terminal multiplexer instead of invoking the command on the remote host. The available multiplexers are: * `interactive`: A built-in multiplexer. `interactive` supports running commands on a subset of the connected hosts in parallel * __screen__(1): Runs ssh interactively inside `screen`. ~/.screenrc will be sourced if it exists. * __tmux__(1): Runs ssh interactively inside tmux. * `macterm` (Mac OS X only): Opens a Terminal.app window and creates a tab for each ssh session. You must install the rb-appscript gem before you can use this option. ## SEE ALSO __knife-search__(1) ## AUTHOR Chef was written by Adam Jacob with many contributions from the community. ## DOCUMENTATION This manual page was written by Joshua Timberman . Permission is granted to copy, distribute and / or modify this document under the terms of the Apache 2.0 License. ## CHEF Knife is distributed with Chef. chef-11.8.2/distro/arch/0000755000004100000410000000000012254362222014761 5ustar www-datawww-datachef-11.8.2/distro/arch/etc/0000755000004100000410000000000012254362222015534 5ustar www-datawww-datachef-11.8.2/distro/arch/etc/rc.d/0000755000004100000410000000000012254362222016362 5ustar www-datawww-datachef-11.8.2/distro/arch/etc/rc.d/chef-client0000644000004100000410000000365112254362222020473 0ustar www-datawww-data#!/bin/bash # # Copyright (c) 2009-2010 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. # daemon_bin="/usr/bin/chef-client" daemon_name=$(basename $daemon_bin) PIDF="/var/run/$daemon_name.pid" . /etc/rc.conf . /etc/rc.d/functions . /etc/conf.d/$daemon_name.conf get_pid() { pidof -o %PPID $daemon_name } case "$1" in start) stat_busy "Starting $daemon_name" PID=$(get_pid) if [ -z "$PID" ]; then [ -f $PIDF ] && rm -f $PIDF $daemon_bin --pid $PIDF $CHEF_CLIENT_ARGS if [ $? -gt 0 ]; then stat_fail exit 1 else echo $(get_pid) > $PIDF add_daemon $daemon_name stat_done fi else stat_fail exit 1 fi ;; stop) stat_busy "Stopping $daemon_name daemon" PID=$(get_pid) [ ! -z "$PID" ] && kill $PID &> /dev/null if [ $? -gt 0 ]; then stat_fail exit 1 else rm -f $PIDF &>/dev/null rm_daemon $daemon_name stat_done fi ;; restart) $0 stop sleep 3 $0 start ;; status) stat_busy "Checking $daemon_name status"; ck_status $daemon_name ;; run) stat_busy "Triggering new run of $daemon_name daemon" PID=$(get_pid) [ ! -z "$PID" ] && kill -SIGUSR1 $PID &> /dev/null if [ $? -gt 0 ]; then stat_fail exit 1 else stat_done fi ;; *) echo "usage: $) {start|stop|restart|status|run}" esac chef-11.8.2/distro/arch/etc/rc.d/chef-expander0000644000004100000410000000346012254362222021021 0ustar www-datawww-data#!/bin/bash # # Copyright (c) 2009-2010 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. # daemon_bin="/usr/bin/chef-expander" daemon_name=$(basename $daemon_bin) PIDF="/var/run/$daemon_name.pid" . /etc/rc.conf . /etc/rc.d/functions . /etc/conf.d/$daemon_name.conf get_pid() { pidof -o %PPID $daemon_name } case "$1" in start) stat_busy "Starting $daemon_name" PID=$(get_pid) if [ -z "$PID" ]; then [ -f $PIDF ] && rm -f $PIDF $daemon_bin -P $PIDF $CHEF_EXPANDER_ARGS [ -n "$STARTTIME" ] && sleep $STARTTIME if [ $? -gt 0 ]; then stat_fail exit 1 else echo $(get_pid) > $PIDF add_daemon $daemon_name stat_done fi else stat_fail exit 1 fi ;; stop) stat_busy "Stopping $daemon_name daemon" PID=$(get_pid) [ ! -z "$PID" ] && kill $PID &> /dev/null if [ $? -gt 0 ]; then stat_fail exit 1 else rm -f $PIDF &>/dev/null rm_daemon $daemon_name stat_done fi ;; restart) $0 stop [ -n "$DIETIME" ] && sleep $DIETIME $0 start [ -n "$STARTTIME" ] && sleep $STARTTIME ;; status) stat_busy "Checking $daemon_name status"; ck_status $daemon_name ;; *) echo "usage: $) {start|stop|restart|status}" esac chef-11.8.2/distro/arch/etc/rc.d/chef-server0000644000004100000410000000345412254362222020524 0ustar www-datawww-data#!/bin/bash # # Copyright (c) 2009-2010 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. # daemon_bin="/usr/bin/chef-server" daemon_name=$(basename $daemon_bin) PIDF="/var/run/$daemon_name.pid" . /etc/rc.conf . /etc/rc.d/functions . /etc/conf.d/$daemon_name.conf get_pid() { pidof -o %PPID $daemon_name } case "$1" in start) stat_busy "Starting $daemon_name" PID=$(get_pid) if [ -z "$PID" ]; then [ -f $PIDF ] && rm -f $PIDF $daemon_bin -P $PIDF $CHEF_SERVER_ARGS [ -n "$STARTTIME" ] && sleep $STARTTIME if [ $? -gt 0 ]; then stat_fail exit 1 else echo $(get_pid) > $PIDF add_daemon $daemon_name stat_done fi else stat_fail exit 1 fi ;; stop) stat_busy "Stopping $daemon_name daemon" PID=$(get_pid) [ ! -z "$PID" ] && kill $PID &> /dev/null if [ $? -gt 0 ]; then stat_fail exit 1 else rm -f $PIDF &>/dev/null rm_daemon $daemon_name stat_done fi ;; restart) $0 stop [ -n "$DIETIME" ] && sleep $DIETIME $0 start [ -n "$STARTTIME" ] && sleep $STARTTIME ;; status) stat_busy "Checking $daemon_name status"; ck_status $daemon_name ;; *) echo "usage: $) {start|stop|restart|status}" esac chef-11.8.2/distro/arch/etc/rc.d/chef-server-webui0000644000004100000410000000347012254362222021633 0ustar www-datawww-data#!/bin/bash # # Copyright (c) 2009-2010 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. # daemon_bin="/usr/bin/chef-server-webui" daemon_name=$(basename $daemon_bin) PIDF="/var/run/$daemon_name.pid" . /etc/rc.conf . /etc/rc.d/functions . /etc/conf.d/$daemon_name.conf get_pid() { pidof -o %PPID $daemon_name } case "$1" in start) stat_busy "Starting $daemon_name" PID=$(get_pid) if [ -z "$PID" ]; then [ -f $PIDF ] && rm -f $PIDF $daemon_bin -P $PIDF $CHEF_SERVER_WEBUI_ARGS [ -n "$STARTTIME" ] && sleep $STARTTIME if [ $? -gt 0 ]; then stat_fail exit 1 else echo $(get_pid) > $PIDF add_daemon $daemon_name stat_done fi else stat_fail exit 1 fi ;; stop) stat_busy "Stopping $daemon_name daemon" PID=$(get_pid) [ ! -z "$PID" ] && kill $PID &> /dev/null if [ $? -gt 0 ]; then stat_fail exit 1 else rm -f $PIDF &>/dev/null rm_daemon $daemon_name stat_done fi ;; restart) $0 stop [ -n "$DIETIME" ] && sleep $DIETIME $0 start [ -n "$STARTTIME" ] && sleep $STARTTIME ;; status) stat_busy "Checking $daemon_name status"; ck_status $daemon_name ;; *) echo "usage: $) {start|stop|restart|status}" esac chef-11.8.2/distro/arch/etc/rc.d/chef-solr0000644000004100000410000000345012254362222020171 0ustar www-datawww-data#!/bin/bash # # Copyright (c) 2009-2010 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. # daemon_bin="/usr/bin/chef-solr" daemon_name=$(basename $daemon_bin) PIDF="/var/run/$daemon_name.pid" . /etc/rc.conf . /etc/rc.d/functions . /etc/conf.d/$daemon_name.conf get_pid() { pidof -o %PPID $daemon_name } case "$1" in start) stat_busy "Starting $daemon_name" PID=$(get_pid) if [ -z "$PID" ]; then [ -f $PIDF ] && rm -f $PIDF $daemon_bin -P $PIDF $CHEF_SOLR_ARGS [ -n "$STARTTIME" ] && sleep $STARTTIME if [ $? -gt 0 ]; then stat_fail exit 1 else echo $(get_pid) > $PIDF add_daemon $daemon_name stat_done fi else stat_fail exit 1 fi ;; stop) stat_busy "Stopping $daemon_name daemon" PID=$(get_pid) [ ! -z "$PID" ] && kill $PID &> /dev/null if [ $? -gt 0 ]; then stat_fail exit 1 else rm -f $PIDF &>/dev/null rm_daemon $daemon_name stat_done fi ;; restart) $0 stop [ -n "$DIETIME" ] && sleep $DIETIME $0 start [ -n "$STARTTIME" ] && sleep $STARTTIME ;; status) stat_busy "Checking $daemon_name status"; ck_status $daemon_name ;; *) echo "usage: $) {start|stop|restart|status}" esac chef-11.8.2/distro/arch/etc/conf.d/0000755000004100000410000000000012254362222016703 5ustar www-datawww-datachef-11.8.2/distro/arch/etc/conf.d/chef-solr.conf0000644000004100000410000000033412254362222021434 0ustar www-datawww-dataLOGFILE=/var/log/chef/solr.log CONFIG=/etc/chef/solr.rb USER=chef GROUP=chef # Sleep to give daemon enough time to fully start or stop. DIETIME=5 STARTTIME=5 CHEF_SOLR_ARGS="-d -c $CONFIG -L $LOGFILE -u $USER -g $GROUP" chef-11.8.2/distro/arch/etc/conf.d/chef-client.conf0000644000004100000410000000022712254362222021734 0ustar www-datawww-dataLOGFILE=/var/log/chef/client.log CONFIG=/etc/chef/client.rb INTERVAL=1800 SPLAY=20 CHEF_CLIENT_ARGS="-L $LOGFILE -d -c $CONFIG -i $INTERVAL -s $SPLAY" chef-11.8.2/distro/arch/etc/conf.d/chef-server-webui.conf0000644000004100000410000000045012254362222023073 0ustar www-datawww-dataLOGFILE=/var/log/chef/server-webui.log CONFIG=/etc/chef/webui.rb ADAPTER=thin PORT=4040 USER=chef GROUP=chef # Sleep to give daemon enough time to fully start or stop. STARTTIME=10 DIETIME=5 CHEF_SERVER_WEBUI_ARGS="-p $PORT -e production -d -a $ADAPTER -L $LOGFILE -C $CONFIG -u $USER -G $GROUP" chef-11.8.2/distro/arch/etc/conf.d/chef-expander.conf0000644000004100000410000000033312254362222022262 0ustar www-datawww-dataLOGFILE=/var/log/chef/expander.log CONFIG=/etc/chef/solr.rb USER=chef GROUP=chef # Sleep to give daemon enough time to fully start or stop. DIETIME=5 STARTTIME=5 CHEF_EXPANDER_ARGS="-d -c $CONFIG -L $LOGFILE -n 1 -i 1" chef-11.8.2/distro/arch/etc/conf.d/chef-server.conf0000644000004100000410000000043512254362222021765 0ustar www-datawww-dataLOGFILE=/var/log/chef/server.log CONFIG=/etc/chef/server.rb ADAPTER=thin PORT=4000 USER=chef GROUP=chef # Sleep to give daemon enough time to fully start or stop. STARTTIME=10 DIETIME=5 CHEF_SERVER_ARGS="-p $PORT -e production -d -a $ADAPTER -L $LOGFILE -C $CONFIG -u $USER -G $GROUP" chef-11.8.2/distro/debian/0000755000004100000410000000000012254362222015266 5ustar www-datawww-datachef-11.8.2/distro/debian/etc/0000755000004100000410000000000012254362222016041 5ustar www-datawww-datachef-11.8.2/distro/debian/etc/init.d/0000755000004100000410000000000012254362222017226 5ustar www-datawww-datachef-11.8.2/distro/debian/etc/init.d/chef-client0000755000004100000410000001073312254362222021341 0ustar www-datawww-data#! /bin/sh ### BEGIN INIT INFO # Provides: chef-client # Required-Start: $remote_fs $network # Required-Stop: $remote_fs $network # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start a chef-client. ### END INIT INFO # # Copyright (c) 2009-2010 Opscode, Inc, # # chef-client Startup script for chef-client. # chkconfig: - 99 02 # description: starts up chef-client in daemon mode. PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=$(which chef-client) NAME=chef-client DESC=chef-client PIDFILE=/var/run/chef/client.pid test -x $DAEMON || exit 1 . /lib/lsb/init-functions [ -r /etc/default/$NAME ] && . /etc/default/$NAME if [ ! -d /var/run/chef ]; then mkdir /var/run/chef fi DAEMON_OPTS="-d -P $PIDFILE -c $CONFIG -i $INTERVAL -s $SPLAY" if [ ! -z $LOGFILE ]; then DAEMON_OPTS="${DAEMON_OPTS} -L $LOGFILE" fi running_pid() { pid=$1 name=$2 [ -z "$pid" ] && return 1 [ ! -d /proc/$pid ] && return 1 cmd=`awk '/Name:/ {print $2}' /proc/$pid/status` [ "$cmd" != "$name" ] && return 1 return 0 } running() { [ ! -f "$PIDFILE" ] && return 1 pid=`cat $PIDFILE` running_pid $pid $NAME || return 1 return 0 } start_server() { if [ -z "$DAEMONUSER" ] ; then start_daemon -p $PIDFILE $DAEMON $DAEMON_OPTS errcode=$? else start-stop-daemon --start --quiet --pidfile $PIDFILE \ --chuid $DAEMONUSER \ --exec $DAEMON -- $DAEMON_OPTS errcode=$? fi return $errcode } stop_server() { if [ -z "$DAEMONUSER" ] ; then killproc -p $PIDFILE $DAEMON errcode=$? else start-stop-daemon --stop --quiet --pidfile $PIDFILE \ --user $DAEMONUSER \ --exec $DAEMON errcode=$? fi return $errcode } reload_server() { if [ -z "$DAEMONUSER" ] ; then killproc -p $PIDFILE $DAEMON -HUP errcode=$? else start-stop-daemon --stop --signal HUP --quiet --pidfile $PIDFILE \ --user $DAEMONUSER \ --exec $DAEMON errcode=$? fi return $errcode } run_server() { if [ -z "$DAEMONUSER" ] ; then killproc -p $PIDFILE $DAEMON -USR1 errcode=$? else start-stop-daemon --stop --signal USR1 --quiet --pidfile $PIDFILE \ --user $DAEMONUSER \ --exec $DAEMON errcode=$? fi return $errcode } force_stop() { [ ! -e "$PIDFILE" ] && return if running ; then /bin/kill -15 $pid sleep "$DIETIME"s if running ; then /bin/kill -9 $pid sleep "$DIETIME"s if running ; then echo "Cannot kill $NAME (pid=$pid)!" exit 1 fi fi fi rm -f $PIDFILE } case "$1" in start) log_daemon_msg "Starting $DESC " "$NAME" if running ; then log_progress_msg "apparently already running" log_end_msg 0 exit 0 fi if start_server ; then [ -n "$STARTTIME" ] && sleep $STARTTIME # Wait some time if running ; then log_end_msg 0 else log_end_msg 1 fi else log_end_msg 1 fi ;; stop) log_daemon_msg "Stopping $DESC" "$NAME" if running ; then errcode=0 stop_server || errcode=$? log_end_msg $errcode else log_progress_msg "apparently not running" log_end_msg 0 exit 0 fi ;; force-stop) $0 stop if running; then log_daemon_msg "Stopping (force) $DESC" "$NAME" errcode=0 force_stop || errcode=$? log_end_msg $errcode fi ;; restart|force-reload) log_daemon_msg "Restarting $DESC" "$NAME" errcode=0 if running ; then stop_server || errcode=$? [ -n "$DIETIME" ] && sleep $DIETIME fi start_server || errcode=$? [ -n "$STARTTIME" ] && sleep $STARTTIME running || errcode=$? log_end_msg $errcode ;; status) log_daemon_msg "Checking status of $DESC" "$NAME" if running ; then log_progress_msg "running" log_end_msg 0 else log_progress_msg "apparently not running" log_end_msg 1 exit 3 fi ;; reload) if running; then log_daemon_msg "Reloading $DESC" "$NAME" errcode=0 reload_server || errcode=$? log_end_msg $errcode fi ;; run) if running; then log_daemon_msg "Triggering run of $DESC" "$NAME" errcode=0 run_server || errcode=$? log_end_msg $errcode fi ;; *) N=/etc/init.d/$NAME echo "Usage: $N {start|stop|force-stop|restart|force-reload|status|run}" >&2 exit 1 ;; esac exit 0 chef-11.8.2/distro/debian/etc/init.d/chef-expander0000755000004100000410000000762412254362222021676 0ustar www-datawww-data#! /bin/sh ### BEGIN INIT INFO # Provides: chef-expander # Required-Start: $remote_fs $network rabbitmq-server chef-solr # Required-Stop: $remote_fs $network rabbitmq-server chef-solr # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start a chef-expander. ### END INIT INFO # # Copyright (c) 2009-2010 Opscode, Inc # # chef-expander Startup script for chef-expander. # chkconfig: - 85 02 # description: starts up chef-expander in daemon mode. PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=$(which chef-expander) NAME=chef-expander DESC=chef-expander PIDFILE=/var/run/chef/expander.pid test -x $DAEMON || exit 1 . /lib/lsb/init-functions [ -r /etc/default/$NAME ] && . /etc/default/$NAME if [ ! -d /var/run/chef ]; then mkdir /var/run/chef chown $USER:$GROUP /var/run/chef fi DAEMON_OPTS="-d -c $CONFIG -P $PIDFILE -L $LOGFILE $CHEF_EXPANDER_ARGS" running_pid() { pid=$1 name=$2 [ -z "$pid" ] && return 1 [ ! -d /proc/$pid ] && return 1 cmd=`cat /proc/$pid/cmdline | tr '\000' '\n' | awk 'NR==2'` [ "$cmd" != "$name" ] && return 1 return 0 } running() { [ ! -f "$PIDFILE" ] && return 1 pid=`cat $PIDFILE` running_pid $pid $DAEMON || return 1 return 0 } start_server() { if [ -z "$DAEMONUSER" ] ; then start_daemon -p $PIDFILE $DAEMON $DAEMON_OPTS errcode=$? else start-stop-daemon --start --quiet --pidfile $PIDFILE \ --chuid $DAEMONUSER \ --exec $DAEMON -- $DAEMON_OPTS errcode=$? fi return $errcode } stop_server() { if [ -z "$DAEMONUSER" ] ; then killproc -p $PIDFILE $DAEMON errcode=$? else start-stop-daemon --stop --quiet --pidfile $PIDFILE \ --user $DAEMONUSER \ --exec $DAEMON errcode=$? fi return $errcode } reload_server() { [ ! -f "$PIDFILE" ] && return 1 pid=pidofproc $PIDFILE # This is the daemon's pid /bin/kill -1 $pid return $? } force_stop() { [ ! -e "$PIDFILE" ] && return if running ; then /bin/kill -15 $pid sleep "$DIETIME"s if running ; then /bin/kill -9 $pid sleep "$DIETIME"s if running ; then echo "Cannot kill $NAME (pid=$pid)!" exit 1 fi fi fi rm -f $PIDFILE } case "$1" in start) log_daemon_msg "Starting $DESC " "$NAME" if running ; then log_progress_msg "apparently already running" log_end_msg 0 exit 3 fi if start_server ; then [ -n "$STARTTIME" ] && sleep $STARTTIME # Wait some time if running ; then log_end_msg 0 else log_end_msg 1 fi else log_end_msg 1 fi ;; stop) log_daemon_msg "Stopping $DESC" "$NAME" if running ; then errcode=0 stop_server || errcode=$? log_end_msg $errcode else log_progress_msg "apparently not running" log_end_msg 0 exit 0 fi ;; force-stop) $0 stop if running; then log_daemon_msg "Stopping (force) $DESC" "$NAME" errcode=0 force_stop || errcode=$? log_end_msg $errcode fi ;; restart|force-reload) log_daemon_msg "Restarting $DESC" "$NAME" errcode=0 stop_server || errcode=$? [ -n "$DIETIME" ] && sleep $DIETIME start_server || errcode=$? [ -n "$STARTTIME" ] && sleep $STARTTIME running || errcode=$? log_end_msg $errcode ;; status) log_daemon_msg "Checking status of $DESC" "$NAME" if running ; then log_progress_msg "running" log_end_msg 0 else log_progress_msg "apparently not running" log_end_msg 1 exit 1 fi ;; reload) log_warning_msg "Reloading $NAME daemon: not implemented, as the daemon" log_warning_msg "cannot re-read the config file (use restart)." ;; *) N=/etc/init.d/$NAME echo "Usage: $N {start|stop|force-stop|restart|force-reload|status}" >&2 exit 1 ;; esac exit 0 chef-11.8.2/distro/debian/etc/init.d/chef-server0000755000004100000410000000517012254362222021370 0ustar www-datawww-data#! /bin/sh ### BEGIN INIT INFO # Provides: chef-server # Required-Start: $remote_fs $network rabbitmq-server couchdb # Required-Stop: $remote_fs $network rabbitmq-server couchdb # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start a chef-server. ### END INIT INFO # # Copyright (c) 2009-2010 Opscode, Inc # # chef-server Startup script for chef-server. # chkconfig: - 90 02 # description: starts up chef-server webui. PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=$(which chef-server) PIDFILE=/var/run/chef/server.%s.pid MAINPID=/var/run/chef/server.main.pid NAME=chef-server DESC=chef-server test -x $DAEMON || exit 1 . /lib/lsb/init-functions [ -r /etc/default/$NAME ] && . /etc/default/$NAME if [ ! -d /var/run/chef ]; then mkdir /var/run/chef chown $USER:$GROUP /var/run/chef fi DAEMON_OPTS="-p $PORT -e production -d -a $ADAPTER -P $PIDFILE -L $LOGFILE -C $CONFIG -u $USER -G $GROUP" running() { [ ! -f "$MAINPID" ] && return 1 pid=`cat $MAINPID` [ -z "$pid" ] && return 1 [ ! -d /proc/$pid ] && return 1 (ps -fp $pid | egrep -q "merb.*(merb : master|worker.*$PORT)") || return 1 return 0 } start_server() { $DAEMON $DAEMON_OPTS errcode=$? return $errcode } stop_server() { $DAEMON -K all -P $PIDFILE errcode=$? return $errcode } reload_server() { stop_server [ -n "$DIETIME" ] && sleep $DIETIME start_server [ -n "$STARTTIME" ] && sleep $STARTTIME } case "$1" in start) log_daemon_msg "Starting $DESC " if running ; then log_progress_msg "apparently already running" log_end_msg 0 exit 0 fi if start_server ; then [ -n "$STARTTIME" ] && sleep $STARTTIME # Wait some time if running ; then log_end_msg 0 else log_end_msg 1 fi else log_end_msg 1 fi ;; stop) log_daemon_msg "Stopping $DESC" if running ; then errcode=0 stop_server || errcode=$? log_end_msg $errcode else log_progress_msg "apparently not running" log_end_msg 0 exit 0 fi ;; restart|force-reload) log_daemon_msg "Restarting $DESC" errcode=0 reload_server running && errcode=$? log_end_msg $errcode ;; status) log_daemon_msg "Checking status of $DESC" if running ; then log_progress_msg "running" log_end_msg 0 else log_progress_msg "apparently not running" log_end_msg 1 exit 3 fi ;; *) N=/etc/init.d/$NAME echo "Usage: $N {start|stop|restart|status}" >&2 exit 1 ;; esac exit 0 chef-11.8.2/distro/debian/etc/init.d/chef-server-webui0000755000004100000410000000523612254362222022504 0ustar www-datawww-data#! /bin/sh ### BEGIN INIT INFO # Provides: chef-server-webui # Required-Start: $remote_fs $network chef-server # Required-Stop: $remote_fs $network chef-server # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start a chef-server-webui ### END INIT INFO # # Copyright (c) 2009-2010 Opscode, Inc # # chef-server-webui Startup script for chef-server-webui. # chkconfig: - 95 02 # description: starts up chef-server webui. PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=$(which chef-server-webui) PIDFILE=/var/run/chef/server-webui.%s.pid MAINPID=/var/run/chef/server-webui.main.pid NAME=chef-server-webui DESC=chef-server-webui test -x $DAEMON || exit 1 . /lib/lsb/init-functions [ -r /etc/default/$NAME ] && . /etc/default/$NAME if [ ! -d /var/run/chef ]; then mkdir /var/run/chef chown $USER:$GROUP /var/run/chef fi DAEMON_OPTS="-p $PORT -e production -d -a $ADAPTER -P $PIDFILE -L $LOGFILE -C $CONFIG -u $USER -G $GROUP" running() { [ ! -f "$MAINPID" ] && return 1 pid=`cat $MAINPID` name=$WORKER [ -z "$pid" ] && return 1 [ ! -d /proc/$pid ] && return 1 (ps -fp $pid | egrep -q "merb.*(merb : master|worker.*$PORT)") || return 1 return 0 } start_server() { $DAEMON $DAEMON_OPTS errcode=$? return $errcode } stop_server() { $DAEMON -K all -P $PIDFILE errcode=$? return $errcode } reload_server() { stop_server [ -n "$DIETIME" ] && sleep $DIETIME start_server [ -n "$STARTTIME" ] && sleep $STARTTIME } case "$1" in start) log_daemon_msg "Starting $DESC " if running ; then log_progress_msg "apparently already running" log_end_msg 0 exit 0 fi if start_server ; then [ -n "$STARTTIME" ] && sleep $STARTTIME # Wait some time if running ; then log_end_msg 0 else log_end_msg 1 fi else log_end_msg 1 fi ;; stop) log_daemon_msg "Stopping $DESC" if running ; then errcode=0 stop_server || errcode=$? log_end_msg $errcode else log_progress_msg "apparently not running" log_end_msg 0 exit 0 fi ;; restart|force-reload) log_daemon_msg "Restarting $DESC" errcode=0 reload_server running && errcode=$? log_end_msg $errcode ;; status) log_daemon_msg "Checking status of $DESC" if running ; then log_progress_msg "running" log_end_msg 0 else log_progress_msg "apparently not running" log_end_msg 1 exit 3 fi ;; *) N=/etc/init.d/$NAME echo "Usage: $N {start|stop|restart|status}" >&2 exit 1 ;; esac exit 0 chef-11.8.2/distro/debian/etc/init.d/chef-solr0000755000004100000410000000730712254362222021045 0ustar www-datawww-data#! /bin/sh ### BEGIN INIT INFO # Provides: chef-solr # Required-Start: $remote_fs $network # Required-Stop: $remote_fs $network # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start a chef-solr. ### END INIT INFO # # Copyright (c) 2009-2010 Opscode, Inc # # chef-solr Startup script for chef-solr. # chkconfig: - 84 02 # description: starts up chef-solr in daemon mode. PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=$(which chef-solr) DAEMON_NAME=java NAME=chef-solr DESC=chef-solr PIDFILE=/var/run/chef/solr.pid test -x $DAEMON || exit 1 . /lib/lsb/init-functions [ -r /etc/default/$NAME ] && . /etc/default/$NAME if [ ! -d /var/run/chef ]; then mkdir /var/run/chef chown $USER:$GROUP /var/run/chef fi if [ ! -f $LOGFILE ]; then touch $LOGFILE chown $USER:$GROUP $LOGFILE fi DAEMON_OPTS="-d -P $PIDFILE -c $CONFIG -L $LOGFILE -u $USER -g $GROUP" running_pid() { pid=$1 name=$2 [ -z "$pid" ] && return 1 [ ! -d /proc/$pid ] && return 1 cmd=`cat /proc/$pid/cmdline | tr '\000' '\n' | head -1` [ "$cmd" != "$name" ] && return 1 return 0 } running() { [ ! -f "$PIDFILE" ] && return 1 pid=`cat $PIDFILE` running_pid $pid $DAEMON_NAME || return 1 return 0 } start_server() { start_daemon -p $PIDFILE $DAEMON $DAEMON_OPTS errcode=$? for i in `seq 0 $MAXTRIES` do if running; then errcode=0 break else [ -n "$STARTTIME" ] && sleep $STARTTIME fi done return $errcode } stop_server() { killproc -p $PIDFILE $DAEMON errcode=$? return $errcode } reload_server() { [ ! -f "$PIDFILE" ] && return 1 pid=pidofproc $PIDFILE # This is the daemon's pid /bin/kill -1 $pid return $? } force_stop() { [ ! -e "$PIDFILE" ] && return if running ; then /bin/kill -15 $pid sleep "$DIETIME"s if running ; then /bin/kill -9 $pid sleep "$DIETIME"s if running ; then echo "Cannot kill $NAME (pid=$pid)!" exit 1 fi fi fi rm -f $PIDFILE } case "$1" in start) log_daemon_msg "Starting $DESC " "$NAME" if running ; then log_progress_msg "apparently already running" log_end_msg 0 exit 3 fi if start_server ; then [ -n "$STARTTIME" ] && sleep $STARTTIME # Wait some time if running ; then log_end_msg 0 else log_end_msg 1 fi else log_end_msg 1 fi ;; stop) log_daemon_msg "Stopping $DESC" "$NAME" if running ; then errcode=0 stop_server || errcode=$? log_end_msg $errcode else log_progress_msg "apparently not running" log_end_msg 0 exit 0 fi ;; force-stop) $0 stop if running; then log_daemon_msg "Stopping (force) $DESC" "$NAME" errcode=0 force_stop || errcode=$? log_end_msg $errcode fi ;; restart|force-reload) log_daemon_msg "Restarting $DESC" "$NAME" errcode=0 stop_server || errcode=$? [ -n "$DIETIME" ] && sleep $DIETIME start_server || errcode=$? [ -n "$STARTTIME" ] && sleep $STARTTIME running || errcode=$? log_end_msg $errcode ;; status) log_daemon_msg "Checking status of $DESC" "$NAME" if running ; then log_progress_msg "running" log_end_msg 0 else log_progress_msg "apparently not running" log_end_msg 1 exit 1 fi ;; reload) log_warning_msg "Reloading $NAME daemon: not implemented, as the daemon" log_warning_msg "cannot re-read the config file (use restart)." ;; *) N=/etc/init.d/$NAME echo "Usage: $N {start|stop|force-stop|restart|force-reload|status}" >&2 exit 1 ;; esac exit 0 chef-11.8.2/distro/debian/etc/default/0000755000004100000410000000000012254362222017465 5ustar www-datawww-datachef-11.8.2/distro/debian/etc/default/chef-client0000644000004100000410000000012312254362222021565 0ustar www-datawww-dataLOGFILE=/var/log/chef/client.log CONFIG=/etc/chef/client.rb INTERVAL=1800 SPLAY=20 chef-11.8.2/distro/debian/etc/default/chef-expander0000644000004100000410000000030112254362222022113 0ustar www-datawww-dataLOGFILE=/var/log/chef/expander.log CONFIG=/etc/chef/solr.rb USER=chef GROUP=chef # Sleep to give daemon enough time to fully start or stop. DIETIME=5 STARTTIME=5 CHEF_EXPANDER_ARGS="-n 1 -i 1" chef-11.8.2/distro/debian/etc/default/chef-server0000644000004100000410000000027212254362222021622 0ustar www-datawww-dataLOGFILE=/var/log/chef/server.log CONFIG=/etc/chef/server.rb ADAPTER=thin PORT=4000 USER=chef GROUP=chef # Sleep to give daemon enough time to fully start or stop. STARTTIME=10 DIETIME=5 chef-11.8.2/distro/debian/etc/default/chef-server-webui0000644000004100000410000000027712254362222022740 0ustar www-datawww-dataLOGFILE=/var/log/chef/server-webui.log CONFIG=/etc/chef/webui.rb ADAPTER=thin PORT=4040 USER=chef GROUP=chef # Sleep to give daemon enough time to fully start or stop. STARTTIME=10 DIETIME=5 chef-11.8.2/distro/debian/etc/default/chef-solr0000644000004100000410000000025212254362222021271 0ustar www-datawww-dataLOGFILE=/var/log/chef/solr.log CONFIG=/etc/chef/solr.rb USER=chef GROUP=chef # Sleep to give daemon enough time to fully start or stop. DIETIME=5 STARTTIME=5 MAXTRIES=20 chef-11.8.2/distro/debian/etc/init/0000755000004100000410000000000012254362222017004 5ustar www-datawww-datachef-11.8.2/distro/debian/etc/init/chef-solr.conf0000644000004100000410000000050712254362222021537 0ustar www-datawww-data# chef-solr - Chef Solr # # Chef Solr provides Solr search for Chef Server description "Chef Solr" start on filesystem stop on runlevel [!2345] respawn respawn limit 5 30 pre-start script test -x /usr/bin/chef-solr || { stop; exit 1; } end script exec /usr/bin/chef-solr -c /etc/chef/solr.rb -L /var/log/chef/solr.log chef-11.8.2/distro/debian/etc/init/chef-client.conf0000644000004100000410000000055612254362222022042 0ustar www-datawww-data# chef-client - Chef Configuration Management Client # # Chef Client provides the Chef configuration management daemon description "Chef Client" start on filesystem stop on runlevel [!2345] respawn respawn limit 5 30 pre-start script test -x /usr/bin/chef-client || { stop; exit 1; } end script exec /usr/bin/chef-client -i 1800 -L /var/log/chef/client.log chef-11.8.2/distro/debian/etc/init/chef-server-webui.conf0000644000004100000410000000062512254362222023200 0ustar www-datawww-data# chef-server-webui - Chef Server WebUI # # Chef Server WebUI provides the browser-accessible UI to the Chef Server API description "Chef Server WebUI" start on filesystem stop on runlevel [!2345] respawn respawn limit 5 30 pre-start script test -x /usr/bin/chef-server-webui || { stop; exit 1; } end script exec /usr/bin/chef-server-webui -e production -p 4040 -L /var/log/chef/server-webui.log chef-11.8.2/distro/debian/etc/init/chef-expander.conf0000644000004100000410000000056212254362222022367 0ustar www-datawww-data# chef-expander - Chef Expander # # Chef Expander provides indexing of Solr for Chef Server description "Chef Expander" start on filesystem stop on runlevel [!2345] respawn respawn limit 5 30 pre-start script test -x /usr/bin/chef-expander || { stop; exit 1; } end script exec /usr/bin/chef-expander -c /etc/chef/solr.rb -L /var/log/chef/expander.log -n 1 -i 1 chef-11.8.2/distro/debian/etc/init/chef-server.conf0000644000004100000410000000052212254362222022063 0ustar www-datawww-data# chef-server - Chef Server # # Chef Server provides the Chef API server description "Chef Server API" start on filesystem stop on runlevel [!2345] respawn respawn limit 5 30 pre-start script test -x /usr/bin/chef-server || { stop; exit 1; } end script exec /usr/bin/chef-server -e production -p 4000 -L /var/log/chef/server.log chef-11.8.2/distro/redhat/0000755000004100000410000000000012254362222015313 5ustar www-datawww-datachef-11.8.2/distro/redhat/etc/0000755000004100000410000000000012254362222016066 5ustar www-datawww-datachef-11.8.2/distro/redhat/etc/init.d/0000755000004100000410000000000012254362222017253 5ustar www-datawww-datachef-11.8.2/distro/redhat/etc/init.d/chef-client0000644000004100000410000000460712254362222021366 0ustar www-datawww-data#!/bin/bash # # chef-client Startup script for the Chef client # # chkconfig: - 98 02 # description: Client component of the Chef systems integration framework. ### BEGIN INIT INFO # Provides: chef-client # Required-Start: $local_fs $network $remote_fs # Required-Stop: $local_fs $network $remote_fs # Should-Start: $named $time # Should-Stop: $named $time # Short-Description: Startup script for the Chef client # Description: Client component of the Chef systems integration framework. ### END INIT INFO # Source function library . /etc/init.d/functions exec="/usr/bin/chef-client" prog="chef-client" [ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog config=${CONFIG-/etc/chef/client.rb} pidfile=${PIDFILE-/var/run/chef/client.pid} lockfile=${LOCKFILE-/var/lock/subsys/$prog} logfile=${LOGFILE-/var/log/chef/client.log} interval=${INTERVAL-1800} splay=${SPLAY-20} options=${OPTIONS-} start() { [ -x $exec ] || exit 5 [ -f $config ] || exit 6 echo -n $"Starting $prog: " daemon chef-client -d -c "$config" -L "$logfile" -P "$pidfile" -i "$interval" -s "$splay" "$options" retval=$? echo [ $retval -eq 0 ] && touch $lockfile return $retval } stop() { echo -n $"Stopping $prog: " killproc -p $pidfile chef-client retval=$? echo [ $retval -eq 0 ] && rm -f $lockfile return $retval } restart () { stop start } reload() { echo -n $"Reloading $prog: " killproc -p $pidfile chef-client -HUP retval=$? echo return $retval } run() { echo -n $"Triggering run of $prog: " killproc -p $pidfile chef-client -USR1 retval=$? echo return $retval } force_reload() { restart } rh_status() { # run checks to determine if the service is running or use generic status status -p $pidfile $prog } rh_status_q() { rh_status >/dev/null 2>&1 } case "$1" in start) rh_status_q && exit 0 $1 ;; stop) rh_status_q || exit 0 $1 ;; restart) $1 ;; reload) rh_status_q || exit 7 $1 ;; force-reload) force_reload ;; status) rh_status ;; condrestart|try-restart) rh_status_q || exit 0 restart ;; run) $1 ;; *) echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|run}" exit 2 esac exit $? chef-11.8.2/distro/redhat/etc/init.d/chef-expander0000644000004100000410000000412312254362222021707 0ustar www-datawww-data#!/bin/bash # # chef-expander Startup script for the Chef search indexer # # chkconfig: - 95 05 # description: Search indexer component of the Chef Server. ### BEGIN INIT INFO # Provides: chef-expander # Required-Start: $local_fs $network $remote_fs chef-solr rabbitmq-server # Required-Stop: $local_fs $network $remote_fs chef-solr rabbitmq-server # Should-Start: $named $time # Should-Stop: $named $time # Short-Description: Startup script for the Chef search indexer # Description: Search indexer component of the Chef Server. ### END INIT INFO # Source function library . /etc/init.d/functions exec="/usr/bin/chef-expander" prog="chef-expander" [ -f /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog config=${CONFIG-/etc/chef/expander.rb} pidfile=${PIDFILE-/var/run/chef/expander.pid} lockfile=${LOCKFILE-/var/lock/subsys/$prog} logfile=${LOGFILE-/var/log/chef/expander.log} options=${OPTIONS-} start() { [ -x $exec ] || exit 5 [ -f $config ] || exit 6 echo -n $"Starting $prog: " daemon $prog -d -c "$config" -L "$logfile" -P "$pidfile" "$options" retval=$? echo [ $retval -eq 0 ] && touch $lockfile return $retval } stop() { echo -n $"Stopping $prog: " killproc -p $pidfile $prog retval=$? echo [ $retval -eq 0 ] && rm -f $lockfile return $retval } restart () { stop start } reload() { restart } force_reload() { restart } rh_status() { # run checks to determine if the service is running or use generic status status -p $pidfile $prog } rh_status_q() { rh_status >/dev/null 2>&1 } case "$1" in start) rh_status_q && exit 0 $1 ;; stop) rh_status_q || exit 0 $1 ;; restart) $1 ;; reload) rh_status_q || exit 7 $1 ;; force-reload) force_reload ;; status) rh_status ;; condrestart|try-restart) rh_status_q || exit 0 restart ;; *) echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" exit 2 esac exit $? chef-11.8.2/distro/redhat/etc/init.d/chef-server0000644000004100000410000000456712254362222021423 0ustar www-datawww-data#!/bin/bash # # chef-server Startup script for chef-server # # chkconfig: - 96 04 # description: Server component of the Chef systems integration framework. ### BEGIN INIT INFO # Provides: chef-server # Required-Start: $local_fs $network $remote_fs chef-solr chef-expander # Required-Stop: $local_fs $network $remote_fs chef-solr chef-expander # Should-Start: $named $time # Should-Stop: $named $time # Short-Description: Startup script for chef-server # Description: Server component of the Chef systems integration framework. ### END INIT INFO # Source function library . /etc/init.d/functions exec="/usr/bin/chef-server" prog="chef-server" [ -f /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog config=${CONFIG-/etc/chef/server.rb} pidfile=${PIDFILE-/var/run/chef/server.main.pid} lockfile=${LOCKFILE-/var/lock/subsys/$prog} logfile=${LOGFILE-/var/log/chef/server.log} port=${PORT-4000} env=${ENVIRONMENT-production} adapter=${ADAPTER-thin} childpidfiles=${CHILDPIDFILES-/var/run/chef/server.%s.pid} user=${SERVER_USER-chef} group=${SERVER_GROUP-chef} options=${OPTIONS-} start() { [ -x $exec ] || exit 5 [ -f $config ] || exit 6 echo -n $"Starting $prog: " daemon $prog -d -C "$config" -L "$logfile" -p "$port" -e "$env" \ -a "$adapter" -P "$childpidfiles" -u "$user" -G "$group" \ "$options" "&>/dev/null" retval=$? echo [ $retval -eq 0 ] && touch $lockfile return $retval } stop() { echo -n $"Stopping $prog: " killproc -p $pidfile $prog retval=$? echo [ $retval -eq 0 ] && rm -f $lockfile return $retval } restart () { stop start } reload() { restart } force_reload() { restart } rh_status() { # run checks to determine if the service is running or use generic status status -p $pidfile $prog } rh_status_q() { rh_status >/dev/null 2>&1 } case "$1" in start) rh_status_q && exit 0 $1 ;; stop) rh_status_q || exit 0 $1 ;; restart) $1 ;; reload) rh_status_q || exit 7 $1 ;; force-reload) force_reload ;; status) rh_status ;; condrestart|try-restart) rh_status_q || exit 0 restart ;; *) echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" exit 2 esac exit $? chef-11.8.2/distro/redhat/etc/init.d/chef-server-webui0000644000004100000410000000463712254362222022532 0ustar www-datawww-data#!/bin/bash # # chef-server-webui Startup script for chef-server-webui # # chkconfig: - 97 03 # description: Server WebUI component of the Chef systems integration framework. ### BEGIN INIT INFO # Provides: chef-server-webui # Required-Start: $local_fs $network $remote_fs chef-sever # Required-Stop: $local_fs $network $remote_fs chef-server # Should-Start: $named $time # Should-Stop: $named $time # Short-Description: Startup script for chef-server-webui # Description: Server WebUI component of the Chef systems integration framework. ### END INIT INFO # Source function library . /etc/init.d/functions exec="/usr/bin/chef-server-webui" prog="chef-server-webui" [ -f /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog config=${CONFIG-/etc/chef/webui.rb} pidfile=${PIDFILE-/var/run/chef/server-webui.main.pid} lockfile=${LOCKFILE-/var/lock/subsys/$prog} logfile=${LOGFILE-/var/log/chef/server-webui.log} port=${PORT-4040} env=${ENVIRONMENT-production} adapter=${ADAPTER-thin} childpidfiles=${CHILDPIDFILES-/var/run/chef/server-webui.%s.pid} user=${SERVER_USER-chef} group=${SERVER_GROUP-chef} options=${OPTIONS-} start() { [ -x $exec ] || exit 5 [ -f $config ] || exit 6 echo -n $"Starting $prog: " daemon $prog -d -C "$config" -L "$logfile" -p "$port" -e "$env" \ -a "$adapter" -P "$childpidfiles" -u "$user" -G "$group" \ "$options" "&>/dev/null" retval=$? echo [ $retval -eq 0 ] && touch $lockfile return $retval } stop() { echo -n $"Stopping $prog: " killproc -p $pidfile $prog retval=$? echo [ $retval -eq 0 ] && rm -f $lockfile return $retval } restart () { stop start } reload() { restart } force_reload() { restart } rh_status() { # run checks to determine if the service is running or use generic status status -p $pidfile $prog } rh_status_q() { rh_status >/dev/null 2>&1 } case "$1" in start) rh_status_q && exit 0 $1 ;; stop) rh_status_q || exit 0 $1 ;; restart) $1 ;; reload) rh_status_q || exit 7 $1 ;; force-reload) force_reload ;; status) rh_status ;; condrestart|try-restart) rh_status_q || exit 0 restart ;; *) echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" exit 2 esac exit $? chef-11.8.2/distro/redhat/etc/init.d/chef-solr0000644000004100000410000000376712254362222021075 0ustar www-datawww-data#!/bin/bash # # chef-solr Startup script for the SOLR search engine # # chkconfig: - 94 06 # description: SOLR search engine for the Chef Server. ### BEGIN INIT INFO # Provides: chef-solr # Required-Start: $local_fs $network $remote_fs # Required-Stop: $local_fs $network $remote_fs # Should-Start: $named $time # Should-Stop: $named $time # Short-Description: Startup script for the SOLR search engine # Description: SOLR search engine for the Chef Server. ### END INIT INFO # Source function library . /etc/init.d/functions exec="/usr/bin/chef-solr" prog="chef-solr" [ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog config=${CONFIG-/etc/chef/solr.rb} pidfile=${PIDFILE-/var/run/chef/solr.pid} lockfile=${LOCKFILE-/var/lock/subsys/$prog} logfile=${LOGFILE-/var/log/chef/solr.log} options=${OPTIONS-} start() { [ -x $exec ] || exit 5 [ -f $config ] || exit 6 echo -n $"Starting $prog: " daemon $prog -d -c "$config" -L "$logfile" -P "$pidfile" "$options" retval=$? echo [ $retval -eq 0 ] && touch $lockfile return $retval } stop() { echo -n $"Stopping $prog: " killproc -p $pidfile $prog retval=$? echo [ $retval -eq 0 ] && rm -f $lockfile return $retval } restart () { stop start } reload() { restart } force_reload() { restart } rh_status() { # run checks to determine if the service is running or use generic status status -p $pidfile $prog } rh_status_q() { rh_status >/dev/null 2>&1 } case "$1" in start) rh_status_q && exit 0 $1 ;; stop) rh_status_q || exit 0 $1 ;; restart) $1 ;; reload) rh_status_q || exit 7 $1 ;; force-reload) force_reload ;; status) rh_status ;; condrestart|try-restart) rh_status_q || exit 0 restart ;; *) echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" exit 2 esac exit $? chef-11.8.2/distro/redhat/etc/sysconfig/0000755000004100000410000000000012254362222020072 5ustar www-datawww-datachef-11.8.2/distro/redhat/etc/sysconfig/chef-client0000644000004100000410000000073412254362222022202 0ustar www-datawww-data# Configuration file for the chef-client service #CONFIG=/etc/chef/client.rb #PIDFILE=/var/run/chef/client.pid #LOCKFILE=/var/lock/subsys/chef-client #LOGFILE=/var/log/chef/client.log # Sleep interval between runs. # This value is in seconds. #INTERVAL=1800 # Maximum amount of random delay before starting a run. Prevents every client # from contacting the server at the exact same time. # This value is in seconds. #SPLAY=20 # Any additional chef-client options. #OPTIONS= chef-11.8.2/distro/redhat/etc/sysconfig/chef-expander0000644000004100000410000000032612254362222022527 0ustar www-datawww-data# Configuration file for the chef-expander service #PIDFILE=/var/run/chef/expander.pid #CONFIG=/etc/chef/expander.rb #LOGFILE=/var/log/chef/expander.log # Any additional chef-expander options. OPTIONS="-n 1 -i 1" chef-11.8.2/distro/redhat/etc/sysconfig/chef-server0000644000004100000410000000055212254362222022230 0ustar www-datawww-data# Configuration file for the chef-server service #CONFIG=/etc/chef/server.rb #PIDFILE=/var/run/chef/server.pid #LOCKFILE=/var/lock/subsys/chef-server #LOGFILE=/var/log/chef/server.log #PORT=4000 #ENVIRONMENT=production #ADAPTER=thin #CHILDPIDFILES=/var/run/chef/server.%s.pid #SERVER_USER=chef #SERVER_GROUP=chef # Any additional chef-server options. #OPTIONS= chef-11.8.2/distro/redhat/etc/sysconfig/chef-server-webui0000644000004100000410000000061512254362222023341 0ustar www-datawww-data# Configuration file for the chef-server-webui service #CONFIG=/etc/chef/webui.rb #PIDFILE=/var/run/chef/server-webui.pid #LOCKFILE=/var/lock/subsys/chef-server-webui #LOGFILE=/var/log/chef/server-webui.log #PORT=4040 #ENVIRONMENT=production #ADAPTER=thin #CHILDPIDFILES=/var/run/chef/server-webui.%s.pid #SERVER_USER=chef #SERVER_GROUP=chef # Any additional chef-server-webui options. #OPTIONS= chef-11.8.2/distro/redhat/etc/sysconfig/chef-solr0000644000004100000410000000037512254362222021704 0ustar www-datawww-data# Configuration file for the chef-solr service #CONFIG=/etc/chef/solr.rb #PIDFILE=/var/run/chef/solr.pid #LOCKFILE=/var/lock/subsys/chef-solr #LOGFILE=/var/log/chef/solr.log # Options for Java. Need to start with -j followed by options. #OPTIONS="-j " chef-11.8.2/distro/redhat/etc/logrotate.d/0000755000004100000410000000000012254362222020310 5ustar www-datawww-datachef-11.8.2/distro/redhat/etc/logrotate.d/chef-client0000644000004100000410000000021612254362222022413 0ustar www-datawww-data/var/log/chef/client.log { rotate 12 weekly compress postrotate /etc/init.d/chef-client condrestart >/dev/null || : endscript } chef-11.8.2/distro/redhat/etc/logrotate.d/chef-expander0000644000004100000410000000022212254362222022740 0ustar www-datawww-data/var/log/chef/expander.log { rotate 12 weekly compress postrotate /etc/init.d/chef-expander condrestart >/dev/null || : endscript } chef-11.8.2/distro/redhat/etc/logrotate.d/chef-server0000644000004100000410000000021612254362222022443 0ustar www-datawww-data/var/log/chef/server.log { rotate 12 weekly compress postrotate /etc/init.d/chef-server condrestart >/dev/null || : endscript } chef-11.8.2/distro/redhat/etc/logrotate.d/chef-server-webui0000644000004100000410000000023212254362222023552 0ustar www-datawww-data/var/log/chef/server-webui.log { rotate 12 weekly compress postrotate /etc/init.d/chef-server-webui condrestart >/dev/null || : endscript } chef-11.8.2/distro/redhat/etc/logrotate.d/chef-solr0000644000004100000410000000021212254362222022110 0ustar www-datawww-data/var/log/chef/solr.log { rotate 12 weekly compress postrotate /etc/init.d/chef-solr condrestart >/dev/null || : endscript }