diff options
34 files changed, 1850 insertions, 140 deletions
@@ -1,3 +1,32 @@ +Thu Mar 5 19:51:02 PST 2009 +Release Notes - Chef - Version 0.5.6 +http://tickets.opscode.com + +** Bug + * [CHEF-112] - FreeBSD service provider does not enable service in /etc/rc.conf if service_enable line is not already there + * [CHEF-115] - Remote file resource appears to have reserved words that if used, lead to a 404 error + * [CHEF-118] - FreeBSD package provider can not read the candidate version of the port "php5-mysql" + * [CHEF-119] - FreeBSD service provider uses incorrect name for enabling MySQL server in /etc/rc.conf + * [CHEF-126] - chef session_secret_key is hard-coded + * [CHEF-132] - cron resource should check integer values and convert to string + * [CHEF-138] - remote_directory doesn't work + * [CHEF-139] - log_level doesn't affect the actual log level + * [CHEF-141] - remote_file with URL source does not obey http 301 redirects + * [CHEF-149] - chef-client banner + +** Improvement + * [CHEF-54] - chef-server should be a merb slice + * [CHEF-102] - display template error line numbers to aid debugging + * [CHEF-140] - Chef client should know how to use client certs + * [CHEF-146] - Should be able to run features from scratch, starting couch and other deps + * [CHEF-150] - Resource names are limited to one underscore + * [CHEF-152] - The mount resource should be able to add/remove entries in /etc/fstab + +** New Feature + * [CHEF-80] - rpm package provider + * [CHEF-93] - mount / filesystem provider and resource type + * [CHEF-130] - Cucumber integration testing + Fri Feb 13 12:26:07 PST 2009 Release Notes - Chef - Version 0.5.4 http://tickets.opscode.com/ @@ -11,7 +11,8 @@ Contributors and Copyright holders: * Copyright 2008, Ezra Zygmuntowicz <ezra@engineyard.com> * Copyright 2009, Sean Cribbs <seancribbs@gmail.com> * Copyright 2009, Christopher Brown <cb@opscode.com> - + * Copyright 2009, Thom May <thom@clearairturbulence.org> + Chef incorporates code modified from Open4 (http://www.codeforpeople.com/lib/ruby/open4/), which was written by Ara T. Howard. Chef incorporates code modified from Merb (http://www.merbivore.com), which is Copyright (c) 2008 Engine Yard. diff --git a/chef-server/NOTICE b/chef-server/NOTICE deleted file mode 100644 index 165a89d0d5..0000000000 --- a/chef-server/NOTICE +++ /dev/null @@ -1,17 +0,0 @@ -Chef NOTICE -=========== - -Developed at Opscode (http://www.opscode.com). - -Contributors and Copyright holders: - - * Copyright 2008, Adam Jacob <adam@opscode.com> - * Copyright 2008, Arjuna Christensen <aj@hjksolutions.com> - * Copyright 2008, Bryan McLellan <btm@loftninjas.org> - * Copyright 2008, Ezra Zygmuntowicz <ezra@engineyard.com> - * Copyright 2008, Sean Cribbs <seancribbs@gmail.com> - * Copyright 2009, Christopher Brown <cb@opscode.com> - -Chef incorporates code modified from Open4 (http://www.codeforpeople.com/lib/ruby/open4/), which was written by Ara T. Howard. - -Chef incorporates code modified from Merb (http://www.merbivore.com), which is Copyright (c) 2008 Engine Yard. diff --git a/chef-server/Rakefile b/chef-server/Rakefile index c5a05d3b8f..49baae0e82 100644 --- a/chef-server/Rakefile +++ b/chef-server/Rakefile @@ -10,7 +10,7 @@ require 'chef' include FileUtils GEM = "chef-server" -CHEF_SERVER_VERSION = "0.5.5" +CHEF_SERVER_VERSION = "0.5.7" AUTHOR = "Opscode" EMAIL = "chef@opscode.com" HOMEPAGE = "http://wiki.opscode.com/display/chef" diff --git a/chef-server/chef-server.gemspec b/chef-server/chef-server.gemspec index 24728c3075..94a4b02c87 100644 --- a/chef-server/chef-server.gemspec +++ b/chef-server/chef-server.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = %q{chef-server} - s.version = "0.5.5" + s.version = "0.5.7" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Adam Jacob"] diff --git a/chef/NOTICE b/chef/NOTICE deleted file mode 100644 index 9c4af6e82d..0000000000 --- a/chef/NOTICE +++ /dev/null @@ -1,11 +0,0 @@ -Chef NOTICE -=========== - -Developed at HJK Solutions (http://www.hjksolutions.com). - -Contributors and Copyright holders: - - * Copyright 2008, Adam Jacob <adam@opscode.com> - * Copyright 2008, Arjuna Christensen <aj@hjksolutions.com> - * Copyright 2008, Ezra Zygmuntowicz <ezra@engineyard.com> -
\ No newline at end of file diff --git a/chef/Rakefile b/chef/Rakefile index faa66847a4..89f4527b54 100644 --- a/chef/Rakefile +++ b/chef/Rakefile @@ -4,7 +4,7 @@ require 'rake/rdoctask' require './tasks/rspec.rb' GEM = "chef" -CHEF_VERSION = "0.5.5" +CHEF_VERSION = "0.5.7" AUTHOR = "Adam Jacob" EMAIL = "adam@opscode.com" HOMEPAGE = "http://wiki.opscode.com/display/chef" @@ -15,7 +15,7 @@ spec = Gem::Specification.new do |s| s.version = CHEF_VERSION s.platform = Gem::Platform::RUBY s.has_rdoc = true - s.extra_rdoc_files = ["README.txt", "LICENSE", 'NOTICE'] + s.extra_rdoc_files = ["README.txt", "LICENSE" ] s.summary = SUMMARY s.description = s.summary s.author = AUTHOR diff --git a/chef/bin/chef-client b/chef/bin/chef-client index 32a3c45fe0..df06e068fd 100755 --- a/chef/bin/chef-client +++ b/chef/bin/chef-client @@ -29,7 +29,7 @@ config = { :config_file => "/etc/chef/client.rb" } opts = OptionParser.new do |opts| - opts.banner = "Usage: #{$0} [-d DIR|-r FILE] (options)" + opts.banner = "Usage: #{$0} (options)" client_option_hash = { :config_file=> { :short=>"-c CONFIG", :long=>"--config CONFIG", :description=>"The Chef Config file to use", :proc=>nil }, :user=> { :short=>"-u USER", :long=>"--user USER", :description=>"User to change uid to before daemonizing", :proc=>nil }, diff --git a/chef/chef.gemspec b/chef/chef.gemspec index 5273922e20..e856856860 100644 --- a/chef/chef.gemspec +++ b/chef/chef.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = %q{chef} - s.version = "0.5.5" + s.version = "0.5.7" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Adam Jacob"] diff --git a/chef/lib/chef.rb b/chef/lib/chef.rb index 1123a0ea4a..0db1c3ba0d 100644 --- a/chef/lib/chef.rb +++ b/chef/lib/chef.rb @@ -27,7 +27,7 @@ require 'chef/config' Dir[File.join(File.dirname(__FILE__), 'chef/mixin/**/*.rb')].sort.each { |lib| require lib } class Chef - VERSION = '0.5.5' + VERSION = '0.5.7' class << self def fatal!(msg, err = -1) diff --git a/chef/lib/chef/platform.rb b/chef/lib/chef/platform.rb index 578ac2ee26..4a56c35de9 100644 --- a/chef/lib/chef/platform.rb +++ b/chef/lib/chef/platform.rb @@ -78,6 +78,7 @@ class Chef :remote_file => Chef::Provider::RemoteFile, :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, diff --git a/chef/lib/chef/provider/mount.rb b/chef/lib/chef/provider/mount.rb new file mode 100644 index 0000000000..da7734653d --- /dev/null +++ b/chef/lib/chef/provider/mount.rb @@ -0,0 +1,121 @@ +# +# Author:: Joshua Timberman (<joshua@opscode.com>) +# 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 initialize(node, new_resource) + super(node, new_resource) + end + + def action_mount + unless @current_resource.mounted + Chef::Log.debug("#{@new_resource}: attempting to mount") + status = mount_fs() + if status + @new_resource.updated = true + Chef::Log.info("#{@new_resource}: mounted succesfully") + end + else + Chef::Log.debug("#{@new_resource}: not mounting, already mounted") + end + end + + def action_umount + if @current_resource.mounted + Chef::Log.debug("#{@new_resource}: attempting to unmount") + status = umount_fs() + if status + @new_resource.updated = true + Chef::Log.info("#{@new_resource}: unmounted succesfully") + end + else + Chef::Log.debug("#{@new_resource}: not unmounting, already unmounted") + end + end + + def action_remount + unless @new_resource.supports[:remount] + raise Chef::Exception::UnsupportedAction, "#{self.to_s} does not support :remount" + else + if @current_resource.mounted + Chef::Log.debug("#{@new_resource}: attempting to remount") + status = remount_fs() + if status + @new_resource.updated = true + Chef::Log.info("#{@new_resource}: remounted succesfully") + end + else + Chef::Log.debug("#{@new_resource}: not mounted, not remounting") + end + end + end + + def action_enable + unless @current_resource.enabled + status = enable_fs + if status + @new_resource.updated = true + Chef::Log.info("#{@new_resource}: enabled successfully") + else + Chef::Log.debug("#{@new_resource}: not enabling, already enabled") + end + end + end + + def action_disable + if @current_resource.enabled + status = disable_fs + if status + @new_resource.updated = true + Chef::Log.info("#{@new_resource}: disabled successfully") + else + Chef::Log.debug("#{@new_resource}: not disabling, already disabled") + end + end + end + + def mount_fs + raise Chef::Exception::UnsupportedAction, "#{self.to_s} does not support :mount" + end + + def umount_fs + raise Chef::Exception::UnsupportedAction, "#{self.to_s} does not support :umount" + end + + def remount_fs + raise Chef::Exception::UnsupportedAction, "#{self.to_s} does not support :remount" + end + + def enable_fs + raise Chef::Exception::UnsupportedAction, "#{self.to_s} does not support :enable" + end + + def disable_fs + raise Chef::Exception::UnsupportedAction, "#{self.to_s} does not support :disable" + end + end + end +end diff --git a/chef/lib/chef/provider/mount/mount.rb b/chef/lib/chef/provider/mount/mount.rb new file mode 100644 index 0000000000..9c9388f12d --- /dev/null +++ b/chef/lib/chef/provider/mount/mount.rb @@ -0,0 +1,153 @@ +# +# Author:: Joshua Timberman (<joshua@opscode.com>) +# 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/command' + +class Chef + class Provider + class Mount + class Mount < Chef::Provider::Mount + + include Chef::Mixin::Command + + def initialize(node, new_resource) + super(node, new_resource) + end + + 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) + Chef::Log.debug("Checking for mount point #{@current_resource.mount_point}") + + # Check to see if the volume is mounted. Last volume entry wins. + mounted = false + popen4("mount") do |pid, stdin, stdout, stderr| + stdout.each do |line| + case line + when /^#{device_regex}\s+on\s+#{@new_resource.mount_point}/ + mounted = true + Chef::Log.debug("Special device #{@new_resource.device} mounted as #{@new_resource.mount_point}") + when /^([\/\w])+\son\s#{@new_resource.mount_point}\s+/ + mounted = false + Chef::Log.debug("Special device #{$~[1]} mounted as #{@new_resource.mount_point}") + end + end + end + @current_resource.mounted(mounted) + + # Check to see if there is a entry in /etc/fstab. Last entry for a volume wins. + enabled = false + ::File.read("/etc/fstab").each do |line| + case line + when /^[#\s]/ + next + when /^#{device_regex}\s+#{@new_resource.mount_point}/ + enabled = true + Chef::Log.debug("Found mount #{@new_resource.device} to #{@new_resource.mount_point} in /etc/fstab") + when /^[\/\w]+\s+#{@new_resource.mount_point}/ + enabled = false + Chef::Log.debug("Found conflicting mount point #{@new_resource.mount_point} in /etc/fstab") + end + end + @current_resource.enabled(enabled) + end + + def mount_fs + unless @current_resource.mounted + command = "mount -t #{@new_resource.fstype}" + command << " -o #{@new_resource.options.join(',')}" unless @new_resource.options.nil? || @new_resource.options.empty? + command << " #{@new_resource.device}" + command << " #{@new_resource.mount_point}" + run_command(:command => command) + Chef::Log.info("Mounted #{@new_resource.mount_point}") + else + Chef::Log.debug("#{@new_resource.mount_point} is already mounted.") + end + end + + def umount_fs + if @current_resource.mounted + command = "umount #{@new_resource.mount_point}" + run_command(:command => command) + Chef::Log.info("Unmounted #{@new_resource.mount_point}") + else + Chef::Log.debug("#{@new_resource.mount_point} is not mounted.") + end + end + + def remount_fs + if @current_resource.mounted and @new_resource.supports[:remount] + command = "mount -o remount #{@new_resource.mount_point}" + run_command(:command => command) + + @new_resource.updated = true + Chef::Log.info("Remounted #{@new_resource.mount_point}") + elsif @current_resource.mounted + umount_fs + sleep 1 + mount_fs + else + Chef::Log.debug("#{@new_resource.mount_point} is not mounted.") + end + end + + def enable_fs + unless @current_resource.enabled + ::File.open("/etc/fstab", "a") do |fstab| + fstab.puts("#{@new_resource.device} #{@new_resource.mount_point} #{@new_resource.fstype} #{@new_resource.options.nil? ? "defaults" : @new_resource.options.join(",")} #{@new_resource.dump} #{@new_resource.pass}") + Chef::Log.info("Enabled #{@new_resource.mount_point}") + end + else + Chef::Log.debug("#{@new_resource.mount_point} is already enabled.") + end + end + + def disable_fs + if @current_resource.enabled + contents = [] + + found = false + ::File.readlines("/etc/fstab").reverse_each do |line| + if !found && line =~ /^#{device_regex}\s+#{@new_resource.mount_point}/ + found = true + Chef::Log.debug("Removing #{@new_resource.mount_point} 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.mount_point} is not enabled") + end + end + + private + def device_regex + ::File.symlink?(@new_resource.device) ? "(?:#{@new_resource.device})|(?:#{::File.readlink(@new_resource.device)})" : @new_resource.device + end + end + end + end +end diff --git a/chef/lib/chef/provider/package/freebsd.rb b/chef/lib/chef/provider/package/freebsd.rb index 8b76a18002..1c37b9c795 100644 --- a/chef/lib/chef/provider/package/freebsd.rb +++ b/chef/lib/chef/provider/package/freebsd.rb @@ -25,44 +25,70 @@ class Chef class Package class Freebsd < Chef::Provider::Package - def load_current_resource - @current_resource = Chef::Resource::Package.new(@new_resource.name) - @current_resource.package_name(@new_resource.package_name) - - status = popen4("pkg_info -E #{@new_resource.package_name}*") do |pid, stdin, stdout, stderr| + def current_installed_version(package_name) + command = "pkg_info -E \"#{package_name}*\"" + status = popen4(command) do |pid, stdin, stdout, stderr| stdout.each do |line| case line - when /^#{@current_resource.package_name}-(.+)/ - @current_resource.version($1) - Chef::Log.debug("Current version is #{@current_resource.version}") + when /^#{package_name}-(.+)/ + return $1 end end end - @current_resource.version(nil) unless @current_resource.version - unless status.exitstatus == 0 || status.exitstatus == 1 - raise Chef::Exception::Package, "pkg_info -E #{@new_resource.package_name} failed - #{status.inspect}!" + raise Chef::Exception::Package, "#{command} failed - #{status.inspect}!" end - - port_path = nil - status = popen4("whereis -s #{@new_resource.package_name}") do |pid, stdin, stdout, stderr| + nil + end + + def port_path_from_name(port_name) + status = popen4("whereis -s #{port_name}") do |pid, stdin, stdout, stderr| stdout.each do |line| case line - when /^#{@new_resource.package_name}:\s+(.+)$/ - @port_path = $1 + when /^#{port_name}:\s+(.+)$/ + return $1 end end end - - makefile = ::File.open("#{@port_path}/Makefile") - makefile.each do |line| - case line - when /^PORTVERSION=\s+(\S+)/ - @candidate_version = $1 - Chef::Log.debug("Ports candidate version is #{@candidate_version}") - end + nil + end + + def ports_candidate_version(port_path) + command = "cd #{port_path}; make -V PORTVERSION" + status = popen4(command) do |pid, stdin, stdout, stderr| + return stdout.readline.strip + end + unless status.exitstatus == 0 || status.exitstatus == 1 + raise Chef::Exception::Package, "#{command} failed - #{status.inspect}!" + end + nil + 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(current_installed_version(@new_resource.package_name)) + Chef::Log.debug("Current version is #{@current_resource.version}") if @current_resource.version + + # if passed ports:package, build DIST_SUBDIR from ports + # if passed a sole word in source that isn't ports, consider it DIST_SUBDIR, install package + # otherwise, the user meant what they said + case @new_resource.source + when /^(?!ports)\w+/ + port_name = @new_resource.source + when /^ports:(\w+)/ + port_name = $1 + else + port_name = @new_resource.package_name end + Chef::Log.debug("Using #{port_name} as package name") + + @port_path = port_path_from_name(port_name) + @candidate_version = ports_candidate_version(@port_path) + Chef::Log.debug("Ports candidate version is #{@candidate_version}") if @candidate_version + @current_resource end diff --git a/chef/lib/chef/provider/package/rpm.rb b/chef/lib/chef/provider/package/rpm.rb new file mode 100644 index 0000000000..93fd607126 --- /dev/null +++ b/chef/lib/chef/provider/package/rpm.rb @@ -0,0 +1,92 @@ +# +# Author:: Joshua Timberman (<joshua@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/provider/package' +require 'chef/mixin/command' +require 'chef/resource/package' + +class Chef + class Provider + class Package + class Rpm < Chef::Provider::Package + + 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 + unless ::File.exists?(@new_resource.source) + raise Chef::Exception::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}" + end + + Chef::Log.debug("Checking rpm status for #{@new_resource.package_name}") + 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 @new_resource.action.include?(:install) + raise Chef::Exception::Package, "Source for package #{@new_resource.name} required for action install" + end + end + + Chef::Log.debug("Checking install state for #{@current_resource.package_name}") + 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("Current version is #{$2}") + @current_resource.version($2) + end + end + end + + unless status.exitstatus == 0 || status.exitstatus == 1 + raise Chef::Exception::Package, "rpm failed - #{status.inspect}!" + end + + @current_resource + end + + def install_package(name, version) + run_command( + :command => "rpm -i #{@new_resource.source}" + ) + end + + def upgrade_package(name, version) + run_command( + :command => "rpm -U #{@new_resource.source}" + ) + end + + def remove_package(name, version) + run_command( + :command => "rpm -e #{@new_resource.name}" + ) + end + end + end + end +end + diff --git a/chef/lib/chef/provider/service/freebsd.rb b/chef/lib/chef/provider/service/freebsd.rb index 78539d96ff..fa43e5225e 100644 --- a/chef/lib/chef/provider/service/freebsd.rb +++ b/chef/lib/chef/provider/service/freebsd.rb @@ -89,10 +89,9 @@ class Chef end if ::File.exists?("/etc/rc.conf") - rcfile = ::File.open("/etc/rc.conf") - rcfile.each do |line| + read_rc_conf.each do |line| case line - when /#{current_resource.service_name}_enable="(\w+)"/ + when /#{service_enable_variable_name}="(\w+)"/ if $1 =~ /[Yy][Ee][Ss]/ @current_resource.enabled true elsif $1 =~ /[Nn][Oo][Nn]?[Oo]?[Nn]?[Ee]?/ @@ -108,40 +107,48 @@ class Chef @current_resource end - def enable_service() - unless @current_resource.enabled - rcfile = ::File.open("/etc/rc.conf", 'r') - lines = rcfile.readlines - lines.collect! do |line| - if line =~ /#{current_resource.service_name}_enable/ - line = "#{current_resource.service_name}_enable=\"YES\"" - else - line = line - 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 + makefile = ::File.open(@init_command) + makefile.each do |line| + case line + when /^name="?(\w+)"?/ + return $1 + "_enable" end - rcfile.close - rcfile = ::File.open("/etc/rc.conf", 'w') - lines.each { |line| rcfile.puts(line) } - rcfile.close end + raise Chef::Exception::Service, "Could not find name=\"service\" line in #{@init_command}" + end + + def set_service_enable(value) + lines = read_rc_conf + # Remove line that set the old value + lines.delete_if { |line| line =~ /#{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() - if @current_resource.enabled - rcfile = ::File.open("/etc/rc.conf", 'r') - lines = rcfile.readlines - lines.collect! do |line| - if line =~ /#{current_resource.service_name}_enable/ - line = "#{current_resource.service_name}_enable=\"NO\"" - else - line = line - end - end - rcfile.close - rcfile = ::File.open("/etc/rc.conf", 'w') - lines.each { |line| rcfile.puts(line) } - rcfile.close - end + set_service_enable("NO") if @current_resource.enabled end end diff --git a/chef/lib/chef/recipe.rb b/chef/lib/chef/recipe.rb index 67be9cc1ef..96e6430620 100644 --- a/chef/lib/chef/recipe.rb +++ b/chef/lib/chef/recipe.rb @@ -167,17 +167,20 @@ class Chef new_recipe.instance_eval(&new_def.recipe) else method_name = method_symbol.to_s - # Otherwise, we're rocking the regular resource call route. + # Otherwise, we're rocking the regular resource call route. rname = nil - mn = method_name.match(/^(.+)_(.+)$/) + regexp = %r{^(.+?)(_(.+))?$} + + mn = method_name.match(regexp) if mn - rname = "Chef::Resource::#{mn[1].capitalize}#{mn[2].capitalize}" - else - short_match = method_name.match(/^(.+)$/) - if short_match - rname = "Chef::Resource::#{short_match[1].capitalize}" + rname = "Chef::Resource::#{mn[1].capitalize}" + + while mn && mn[3] + mn = mn[3].match(regexp) + rname << mn[1].capitalize if mn end end + begin args << @collection args << @node diff --git a/chef/lib/chef/resource/cron.rb b/chef/lib/chef/resource/cron.rb index ed2f695b2e..9e6a03762f 100644 --- a/chef/lib/chef/resource/cron.rb +++ b/chef/lib/chef/resource/cron.rb @@ -37,61 +37,86 @@ class Chef end def minute(arg=nil) + if arg.is_a?(Integer) + converted_arg = arg.to_s + else + converted_arg = arg + end begin if Integer(arg) > 59 then raise RangeError end rescue ArgumentError end set_or_return( :minute, - arg, + 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 Integer(arg) > 23 then raise RangeError end rescue ArgumentError end set_or_return( :hour, - arg, + 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 Integer(arg) > 31 then raise RangeError end rescue ArgumentError end set_or_return( :day, - arg, + 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 Integer(arg) > 12 then raise RangeError end rescue ArgumentError end set_or_return( :month, - arg, + 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 Integer(arg) > 7 then raise RangeError end rescue ArgumentError end set_or_return( :weekday, - arg, + converted_arg, :kind_of => String ) end diff --git a/chef/lib/chef/resource/mount.rb b/chef/lib/chef/resource/mount.rb new file mode 100644 index 0000000000..d807a90d95 --- /dev/null +++ b/chef/lib/chef/resource/mount.rb @@ -0,0 +1,125 @@ +# +# Author:: Joshua Timberman (<joshua@opscode.com>) +# 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 + + def initialize(name, collection=nil, node=nil) + super(name, collection, node) + @resource_name = :mount + @mount_point = name + @device = nil + @fstype = nil + @options = ["defaults"] + @dump = 0 + @pass = 2 + @mounted = false + @enabled = false + @action = :mount + @supports = { :remount => false } + @allowed_actions.push(:mount, :umount, :remount, :enable, :disable) + 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 fstype(arg=nil) + set_or_return( + :fstype, + arg, + :kind_of => [ String ] + ) + end + + def options(arg=nil) + if arg.is_a?(String) + arg.gsub!(/,/, ' ') + converted_arg = arg.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 + + end + end +end + +
\ No newline at end of file diff --git a/chef/lib/chef/rest.rb b/chef/lib/chef/rest.rb index bac6788e52..f712d02ab7 100644 --- a/chef/lib/chef/rest.rb +++ b/chef/lib/chef/rest.rb @@ -1,5 +1,6 @@ # # Author:: Adam Jacob (<adam@opscode.com>) +# Author:: Thom May (<thom@clearairturbulence.org>) # Copyright:: Copyright (c) 2008 Opscode, Inc. # License:: Apache License, Version 2.0 # @@ -217,7 +218,7 @@ class Chef res.body end end - elsif res.kind_of?(Net::HTTPFound) + elsif res.kind_of?(Net::HTTPFound) or res.kind_of?(Net::HTTPMovedPermanently) if res['set-cookie'] @cookies["#{url.host}:#{url.port}"] = res['set-cookie'] end diff --git a/chef/spec/lib/chef/resource/one_two_three_four.rb b/chef/spec/lib/chef/resource/one_two_three_four.rb new file mode 100644 index 0000000000..2b4a884d7d --- /dev/null +++ b/chef/spec/lib/chef/resource/one_two_three_four.rb @@ -0,0 +1,43 @@ +# +# Author:: John Hampton (<john@cleanoffer.com>) +# 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, collection=nil, node=nil) + @resource_name = :one_two_three_four + super(name, collection, node) + end + + def i_can_count(tf) + @i_can_count = tf + end + + def something(arg=nil) + set_if_args(@something, arg) do + case arg + when true, false + @something = arg + end + end + end + end + end +end
\ No newline at end of file diff --git a/chef/spec/unit/provider/mount/mount_spec.rb b/chef/spec/unit/provider/mount/mount_spec.rb new file mode 100644 index 0000000000..ecfee1532d --- /dev/null +++ b/chef/spec/unit/provider/mount/mount_spec.rb @@ -0,0 +1,478 @@ +# +# Author:: Joshua Timberman (<joshua@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")) + +describe Chef::Provider::Mount::Mount, "load_current_resource" do + before(:each) do + @node = mock("Chef::Node", :null_object => true) + @new_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false + ) + @new_resource.stub!(:supports).and_return({:remount => false}) + + @current_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false + ) + + @provider = Chef::Provider::Mount::Mount.new(@node, @new_resource) + Chef::Resource::Mount.stub!(:new).and_return(@current_resource) + ::File.stub!(:read).with("/etc/fstab").and_return "\n" + + @status = mock("Status", :exitstatus => 0) + @provider.stub!(:popen4).and_return(@status) + @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 create a current resource with the name of the new resource" do + Chef::Resource::Mount.should_receive(:new).and_return(@current_resource) + @provider.load_current_resource() + end + + it "should set the current resources mount point to the new resources mount point" do + @current_resource.should_receive(:mount_point).with(@new_resource.mount_point) + @provider.load_current_resource() + end + + it "should set the current resources device to the new resources device" do + @current_resource.should_receive(:device).with(@new_resource.device) + @provider.load_current_resource() + end + + it "should set mounted true if the mount point is found in the mounts list" do + @stdout.stub!(:each).and_yield("#{@new_resource.device} on #{@new_resource.mount_point}") + @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(0) + @current_resource.should_receive(:mounted).with(true) + @provider.load_current_resource() + 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) + + @stdout.stub!(:each).and_yield("#{target} on #{@new_resource.mount_point} type ext3 (rw)\n") + @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(0) + @current_resource.should_receive(:mounted).with(true) + @provider.load_current_resource() + + 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" + + y = @stdout.stub!(:each) + mount.each {|l| y.and_yield(l)} + + @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(0) + @current_resource.should_receive(:mounted).with(true) + @provider.load_current_resource() + 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" + + y = @stdout.stub!(:each) + mount.each {|l| y.and_yield(l)} + + @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(0) + @current_resource.should_receive(:mounted).with(false) + @provider.load_current_resource() + end + + it "mounted should be false if the mount point is not found in the mounts list" do + @stdout.stub!(:each).and_yield("/dev/sdy1 on #{@new_resource.mount_point} type ext3 (rw)\n") + @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(0) + @current_resource.should_receive(:mounted).with(false) + @provider.load_current_resource() + end + + it "should set enabled to true if the mount point is last in fstab" do + fstab = "/dev/sdy1 #{@new_resource.mount_point} ext3 defaults 1 2\n" + fstab << "#{@new_resource.device} #{@new_resource.mount_point} ext3 defaults 1 2\n" + + ::File.stub!(:read).with("/etc/fstab").and_return fstab + + @current_resource.should_receive(:enabled).with(true) + @provider.load_current_resource + 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 = "#{@new_resource.device} #{@new_resource.mount_point} ext3 defaults 1 2\n" + + ::File.stub!(:read).with("/etc/fstab").and_return fstab + + @current_resource.should_receive(:enabled).with(true) + @provider.load_current_resource + 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!(:read).with("/etc/fstab").and_return fstab + + @current_resource.should_receive(:enabled).with(false) + @provider.load_current_resource + + end + + it "should ignore commented lines in fstab " do + fstab = "\# #{@new_resource.device} #{@new_resource.mount_point} ext3 defaults 1 2\n" + ::File.stub!(:read).with("/etc/fstab").and_return fstab + + @current_resource.should_receive(:enabled).with(false) + @provider.load_current_resource + end + + it "should set enabled to false if the mount point is not last in fstab" do + fstab = "#{@new_resource.device} #{@new_resource.mount_point} ext3 defaults 1 2\n" + fstab << "/dev/sdy1 #{@new_resource.mount_point} ext3 defaults 1 2\n" + ::File.stub!(:read).with("/etc/fstab").and_return fstab + + @current_resource.should_receive(:enabled).with(false) + @provider.load_current_resource + end +end + +describe Chef::Provider::Mount::Mount, "mount_fs" do + before(:each) do + @node = mock("Chef::Node", :null_object => true) + @new_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false + ) + @new_resource.stub!(:supports).and_return({:remount => false}) + + @current_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false + ) + + @provider = Chef::Provider::Mount::Mount.new(@node, @new_resource) + Chef::Resource::Mount.stub!(:new).and_return(@current_resource) + @provider.current_resource = @current_resource + + @status = mock("Status", :exitstatus => 0) + @provider.stub!(:popen4).and_return(@status) + @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 mount the filesystem if it is not mounted" do + @stdout.stub!(:each).and_yield("#{@new_resource.device} on #{@new_resource.mount_point}") + @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(0) + @provider.should_receive(:run_command).with({:command => "mount -t #{@new_resource.fstype} #{@new_resource.device} #{@new_resource.mount_point}"}) + @provider.mount_fs() + end + + it "should mount the filesystem with options if options were passed" do + options = "rw,noexec,noauto" + @stdout.stub!(:each).and_yield("#{@new_resource.mount_point} on #{@new_resource.mount_point}") + @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(0) + @new_resource.stub!(:options).and_return(options.split(",")) + @provider.should_receive(:run_command).with({:command => "mount -t #{@new_resource.fstype} -o #{options} #{@new_resource.device} #{@new_resource.mount_point}"}) + @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(:run_command).with({:command => "mount -t #{@new_resource.fstype} #{@new_resource.device} #{@new_resource.mount_point}"}) + @provider.mount_fs() + end + +end + +describe Chef::Provider::Mount::Mount, "umount_fs" do + before(:each) do + @node = mock("Chef::Node", :null_object => true) + @new_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => true + ) + @new_resource.stub!(:supports).and_return({:remount => false}) + + @current_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => true + ) + + @provider = Chef::Provider::Mount::Mount.new(@node, @new_resource) + Chef::Resource::Mount.stub!(:new).and_return(@current_resource) + @provider.current_resource = @current_resource + + @status = mock("Status", :exitstatus => 0) + @provider.stub!(:popen4).and_return(@status) + @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 umount the filesystem if it is mounted" do + @stdout.stub!(:each).and_yield("#{@new_resource.device} on #{@new_resource.mount_point}") + @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(0) + @provider.should_receive(:run_command).with({:command => "umount #{@new_resource.mount_point}"}) + @provider.umount_fs() + end + + it "should not umount the filesystem if it is not mounted" do + @current_resource.stub!(:mounted).and_return(false) + @provider.should_not_receive(:run_command).with({:command => "umount #{@new_resource.mount_point}"}) + @provider.umount_fs() + end +end + +describe Chef::Provider::Mount::Mount, "remount_fs" do + before(:each) do + @node = mock("Chef::Node", :null_object => true) + @new_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => true + ) + @new_resource.stub!(:supports).and_return({:remount => false}) + + @current_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => true + ) + + @provider = Chef::Provider::Mount::Mount.new(@node, @new_resource) + Chef::Resource::Mount.stub!(:new).and_return(@current_resource) + @provider.current_resource = @current_resource + + @status = mock("Status", :exitstatus => 0) + @provider.stub!(:popen4).and_return(@status) + @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 use mount -o remount if remount is supported" do + @new_resource.stub!(:supports).and_return({:remount => true}) + @provider.should_receive(:run_command).with({:command => "mount -o remount #{@new_resource.mount_point}"}) + @provider.remount_fs + end + + it "should umount and mount if remount is not supported" do + @new_resource.stub!(:suports).and_return({:remount => false}) + @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.stub!(:mounted).and_return(false) + @provider.should_not_receive(:run_command).with({:command => "mount -o remount #{@new_resource.mount_point}"}) + @provider.should_not_receive(:umount_fs) + @provider.should_not_receive(:sleep).with(1) + @provider.should_not_receive(:mount_fs) + @provider.remount_fs() + end +end + +describe Chef::Provider::Mount::Mount, "enable_fs" do + before(:each) do + @node = mock("Chef::Node", :null_object => true) + @new_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false, + :options => ["defaults"], + :dump => 0, + :pass => 2 + ) + @new_resource.stub!(:supports).and_return({:remount => false}) + + @current_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false + ) + + @provider = Chef::Provider::Mount::Mount.new(@node, @new_resource) + Chef::Resource::Mount.stub!(:new).and_return(@current_resource) + @provider.current_resource = @current_resource + + @fstab = mock("File", :null_object => true) + end + + it "should enable if enabled isn't true" do + @current_resource.stub!(:enabled).and_return(false) + + ::File.stub!(:open).with("/etc/fstab", "a").and_yield(@fstab) + @fstab.should_receive(:puts).with(/^#{@new_resource.device}\s+#{@new_resource.mount_point}\s+#{@new_resource.fstype}\s+defaults\s+#{@new_resource.dump}\s+#{@new_resource.pass}\s*$/) + + @provider.enable_fs + end + + it "should not enabled if enabled is true" do + @current_resource.stub!(:enabled).and_return(true) + ::File.should_not_receive(:open).with("/etc/fstab", "a").and_yield(@fstab) + + @provider.enable_fs + end +end + +describe Chef::Provider::Mount::Mount, "disable_fs" do + before(:each) do + @node = mock("Chef::Node", :null_object => true) + @new_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false, + :options => ["defaults"], + :dump => 0, + :pass => 2 + ) + @new_resource.stub!(:supports).and_return({:remount => false}) + + @current_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false + ) + + @provider = Chef::Provider::Mount::Mount.new(@node, @new_resource) + Chef::Resource::Mount.stub!(:new).and_return(@current_resource) + @provider.current_resource = @current_resource + + @fstab = mock("File", :null_object => true) + end + + it "should disable if enabled is true" do + @current_resource.stub!(:enabled).and_return(true) + + fstab = ["/dev/sdy1 #{@new_resource.mount_point} ext3 defaults 1 2\n"] + fstab << "#{@new_resource.device} #{@new_resource.mount_point} ext3 defaults 1 2\n" + + ::File.stub!(:readlines).with("/etc/fstab").and_return(fstab) + ::File.stub!(:open).with("/etc/fstab", "w").and_yield(@fstab) + + @fstab.should_receive(:puts).with(fstab[0]).once.ordered + @fstab.should_not_receive(:puts).with(fstab[1]) + + @provider.disable_fs + end + + it "should disable if enabled is true and ignore commented lines" do + @current_resource.stub!(:enabled).and_return(true) + + fstab = ["/dev/sdy1 #{@new_resource.mount_point} ext3 defaults 1 2\n"] + fstab << "#{@new_resource.device} #{@new_resource.mount_point} ext3 defaults 1 2\n" + fstab << "\##{@new_resource.device} #{@new_resource.mount_point} ext3 defaults 1 2\n" + + + ::File.stub!(:readlines).with("/etc/fstab").and_return(fstab) + ::File.stub!(:open).with("/etc/fstab", "w").and_yield(@fstab) + + @fstab.should_receive(:puts).with(fstab[0]).once.ordered + @fstab.should_receive(:puts).with(fstab[2]).once.ordered + + @fstab.should_not_receive(:puts).with(fstab[1]) + + @provider.disable_fs + end + + it "should disable only the last entry if enabled is true" do + @current_resource.stub!(:enabled).and_return(true) + fstab = ["#{@new_resource.device} #{@new_resource.mount_point} ext3 defaults 1 2\n"] + fstab << "/dev/sdy1 #{@new_resource.mount_point} ext3 defaults 1 2\n" + fstab << "#{@new_resource.device} #{@new_resource.mount_point} ext3 defaults 1 2\n" + + + ::File.stub!(:readlines).with("/etc/fstab").and_return(fstab) + ::File.stub!(:open).with("/etc/fstab", "w").and_yield(@fstab) + + @fstab.should_receive(:puts).with(fstab[0]).once.ordered + @fstab.should_receive(:puts).with(fstab[1]).once.ordered + + @fstab.should_not_receive(:puts).with(fstab[2]) + + @provider.disable_fs + 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 diff --git a/chef/spec/unit/provider/mount_spec.rb b/chef/spec/unit/provider/mount_spec.rb new file mode 100644 index 0000000000..7641aafc2d --- /dev/null +++ b/chef/spec/unit/provider/mount_spec.rb @@ -0,0 +1,263 @@ +# +# Author:: Joshua Timberman (<joshua@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")) + +describe Chef::Provider::Mount, "initialize" do + + before(:each) do + @node = mock("Chef::Node", :null_object => true) + @new_resource = mock("Chef::Resource", :null_object => true) + end + + it "should return a Chef::Provider::Mount object" do + provider = Chef::Provider::Mount.new(@node, @new_resource) + provider.should be_a_kind_of(Chef::Provider::Mount) + end + +end + +describe Chef::Provider::Mount, "action_mount" do + before(:each) do + @node = mock("Chef::Node", :null_object => true) + @new_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false, + :enabled => false + ) + @current_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false, + :enabled => false + ) + @provider = Chef::Provider::Mount.new(@node, @new_resource) + @provider.current_resource = @current_resource + @provider.stub!(:mount_fs).and_return(true) + end + + 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.action_mount + 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).with.and_return(true) + @provider.action_mount + end + +end + +describe Chef::Provider::Mount, "action_umount" do + before(:each) do + @node = mock("Chef::Node", :null_object => true) + @new_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false, + :enabled => false + ) + @current_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false, + :enabled => false + ) + @provider = Chef::Provider::Mount.new(@node, @new_resource) + @provider.current_resource = @current_resource + @provider.stub!(:umount_fs).and_return(true) + end + + 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.action_umount + 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).with.and_return(true) + @provider.action_umount + end +end + +describe Chef::Provider::Mount, "action_remount" do + before(:each) do + @node = mock("Chef::Node", :null_object => true) + @new_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false, + :enabled => false + ) + @current_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false, + :enabled => false + ) + @provider = Chef::Provider::Mount.new(@node, @new_resource) + @provider.current_resource = @current_resource + @provider.stub!(:remount_fs).and_return(true) + @current_resource.stub!(:supports).and_return({:remount => true}) + end + + it "should remount the filesystem if remount is support and it is mounted" do + @current_resource.stub!(:mounted).and_return(true) + @provider.should_receive(:remount_fs).and_return(true) + @provider.action_remount + 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).and_return(true) + @provider.action_remount + end +end + +describe Chef::Provider::Mount, "action_enable" do + before(:each) do + @node = mock("Chef::Node", :null_object => true) + @new_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false, + :enabled => false + ) + @current_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false, + :enabled => false + ) + @provider = Chef::Provider::Mount.new(@node, @new_resource) + @provider.current_resource = @current_resource + @provider.stub!(:enable_fs).and_return(true) + end + + it "should enable the mount if it isn't enable" do + @current_resource.stub!(:enabled).and_return(false) + @provider.should_receive(:enable_fs).with.and_return(true) + @provider.action_enable + end + + it "should not enable the mount if it is enabled" do + @current_resource.stub!(:enabled).and_return(true) + @provider.should_not_receive(:enable_fs).with.and_return(true) + @provider.action_enable + end +end + +describe Chef::Provider::Mount, "action_disable" do + before(:each) do + @node = mock("Chef::Node", :null_object => true) + @new_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false, + :enabled => false + ) + @current_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false, + :enabled => false + ) + @provider = Chef::Provider::Mount.new(@node, @new_resource) + @provider.current_resource = @current_resource + @provider.stub!(:disable_fs).and_return(true) + end + + 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.action_disable + 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).with.and_return(true) + @provider.action_disable + end +end + +%w{mount umount remount enable disable}.each do |act| + act_string = "#{act}_fs" + + describe Chef::Provider::Service, act_string do + before(:each) do + @node = mock("Chef::Node", :null_object => true) + @new_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false + ) + @current_resource = mock("Chef::Resource::Mount", + :null_object => true, + :device => "/dev/sdz1", + :name => "/tmp/foo", + :mount_point => "/tmp/foo", + :fstype => "ext3", + :mounted => false + ) + @provider = Chef::Provider::Mount.new(@node, @new_resource) + @provider.current_resource = @current_resource + + end + + it "should raise Chef::Exception::UnsupportedAction on an unsupported action" do + lambda { @provider.send(act_string) }.should raise_error(Chef::Exception::UnsupportedAction) + end + end +end
\ No newline at end of file diff --git a/chef/spec/unit/provider/package/freebsd_spec.rb b/chef/spec/unit/provider/package/freebsd_spec.rb index 786d8057fe..28927bc85d 100644 --- a/chef/spec/unit/provider/package/freebsd_spec.rb +++ b/chef/spec/unit/provider/package/freebsd_spec.rb @@ -37,52 +37,74 @@ describe Chef::Provider::Package::Freebsd, "load_current_resource" do @provider = Chef::Provider::Package::Freebsd.new(@node, @new_resource) Chef::Resource::Package.stub!(:new).and_return(@current_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) - @provider.stub!(:popen4).and_return(true) - - @lines = mock("lines") - @lines.stub!(:each).and_yield("zsh-4.3.6_7") - ::File.stub!(:open).and_return(@lines) + @provider.should_receive(:port_path_from_name).with("zsh").and_return("/usr/ports/zsh") + @provider.should_receive(:ports_candidate_version).with("/usr/ports/zsh").and_return("4.3.6") end 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.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) + @provider.should_receive(:current_installed_version).with("zsh").and_return(nil) @provider.load_current_resource end it "should return a version if the package is installed" do - @stdout.stub!(:each).and_yield("zsh-4.3.6_7") - @lines = mock("lines") - @lines.stub!(:each).and_yield("zsh-4.3.6_7") - ::File.stub!(:open).and_return(@lines) - @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) + @provider.should_receive(:current_installed_version).with("zsh").and_return("4.3.6_7") @current_resource.should_receive(:version).with("4.3.6_7").and_return(true) @provider.load_current_resource end it "should return nil if the package is not installed" do - #@stdout.stub!(:each).and_yield("zsh-4.3.6_7") - @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) + @provider.should_receive(:current_installed_version).with("zsh").and_return(nil) @current_resource.should_receive(:version).with(nil).and_return(true) @provider.load_current_resource end it "should return a candidate version if it exists" do - @stdout.stub!(:each).and_yield("zsh: /usr/ports/shells/zsh") - #@stdout.stub!(:each).and_yield("PORTVERSION= 4.3.6") - @provider.stub!(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - File.stub!(:open) - @makefile.stub!(:each).and_yield("PORTVERSION= 4.3.6") + @provider.should_receive(:current_installed_version).with("zsh").and_return(nil) @provider.load_current_resource @provider.candidate_version.should eql("4.3.6") end end +describe Chef::Provider::Package::Freebsd, "system call wrappers" do + before(:each) do + @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 + @provider.should_receive(:popen4).with('pkg_info -E "zsh*"').and_yield(@pid, @stdin, ["zsh-4.3.6_7"], @stderr).and_return(@status) + @provider.current_installed_version("zsh").should == "4.3.6_7" + end + + it "should return nil when the package is not installed" do + @provider.should_receive(:popen4).with('pkg_info -E "zsh*"').and_yield(@pid, @stdin, [], @stderr).and_return(@status) + @provider.current_installed_version("zsh").should be_nil + end + + it "should return the port path for a valid port name" do + @provider.should_receive(:popen4).with("whereis -s zsh").and_yield(@pid, @stdin, ["zsh: /usr/ports/shells/zsh"], @stderr).and_return(@status) + @provider.port_path_from_name("zsh").should == "/usr/ports/shells/zsh" + end + + it "should return nil for a invalid port name" do + @provider.should_receive(:popen4).with("whereis -s foo").and_yield(@pid, @stdin, ["foo:"], @stderr).and_return(@status) + @provider.port_path_from_name("foo").should be_nil + 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.should_receive(:popen4).with("cd /usr/ports/shells/zsh; make -V PORTVERSION").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) + @stdout.should_receive(:readline).and_return("4.3.6\n") + @provider.ports_candidate_version("/usr/ports/shells/zsh").should == "4.3.6" + end +end + describe Chef::Provider::Package::Freebsd, "install_package" do before(:each) do @node = mock("Chef::Node", :null_object => true) diff --git a/chef/spec/unit/provider/package/rpm_spec.rb b/chef/spec/unit/provider/package/rpm_spec.rb new file mode 100644 index 0000000000..09cbfe97d9 --- /dev/null +++ b/chef/spec/unit/provider/package/rpm_spec.rb @@ -0,0 +1,150 @@ +# +# Author:: Joshua Timberman (<joshua@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")) + +describe Chef::Provider::Package::Rpm, "load_current_resource" do + before(:each) do + @node = mock("Chef::Node", :null_object => true) + + @new_resource = mock("Chef::Resource::Package", + :null_object => true, + :name => "emacs", + :version => nil, + :package_name => "emacs", + :updated => nil, + :source => "/tmp/emacs-21.4-20.el5.i386.rpm" + ) + @current_resource = mock("Chef::Resource::Package", + :null_object => true, + :name => "emacs", + :version => nil, + :package_name => nil, + :updated => nil + ) + + @provider = Chef::Provider::Package::Rpm.new(@node, @new_resource) + Chef::Resource::Package.stub!(:new).and_return(@current_resource) + + @stdin = mock("STDIN", :null_object => true) + @stdout = mock("STDOUT", :null_object => true) + @status = mock("Status", :exitstatus => 0) + @stderr = mock("STDERR", :null_object => true) + @pid = mock("PID", :null_object => true) + @provider.stub!(:popen4).and_return(@status) + ::File.stub!(:exists?).and_return(true) + end + + it "should create a current resource with the name of new_resource" do + Chef::Resource::Package.should_receive(:new).and_return(@current_resource) + @provider.load_current_resource + end + + it "should set the current reource package name to the new resource package name" do + @current_resource.should_receive(:package_name).with(@new_resource.package_name) + @provider.load_current_resource + end + + it "should raise an exception if a source is supplied but not found" do + ::File.stub!(:exists?).and_return(false) + lambda { @provider.load_current_resource }.should raise_error(Chef::Exception::Package) + end + + it "should get the source package version from rpm if provided" do + @stdout.stub!(:each).and_yield("emacs 21.4-20.el5") + @provider.stub!(:popen4).with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@new_resource.source}").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) + @current_resource.should_receive(:package_name).with("emacs") + @new_resource.should_receive(:version).with("21.4-20.el5") + @provider.load_current_resource + end + + it "should return the current version installed if found by rpm" do + @stdout.stub!(:each).and_yield("emacs 21.4-20.el5") + @provider.stub!(:popen4).with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@current_resource.package_name}").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) + @current_resource.should_receive(:version).with("21.4-20.el5") + @provider.load_current_resource + end + + it "should raise an exception if the source is not set but we are installing" do + @new_resource = mock("Chef::Resource::Package", + :null_object => true, + :name => "emacs", + :version => nil, + :package_name => "emacs", + :updated => nil, + :source => nil + ) + @provider = Chef::Provider::Package::Rpm.new(@node, @new_resource) + lambda { @provider.load_current_resource }.should raise_error(Chef::Exception::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.load_current_resource }.should raise_error(Chef::Exception::Package) + end +end + +describe Chef::Provider::Package::Rpm, "install and upgrade" do + before(:each) do + @node = mock("Chef::Node", :null_object => true) + @new_resource = mock("Chef::Resource::Package", + :null_object => true, + :name => "emacs", + :version => nil, + :package_name => "emacs", + :updated => nil, + :source => "/tmp/emacs-21.4-20.el5.i386.rpm" + ) + @provider = Chef::Provider::Package::Rpm.new(@node, @new_resource) + end + + it "should run rpm -i with the package source to install" do + @provider.should_receive(:run_command).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 + @provider.should_receive(:run_command).with({ + :command => "rpm -U /tmp/emacs-21.4-20.el5.i386.rpm" + }) + @provider.upgrade_package("emacs", "21.4-20.el5") + end +end + +describe Chef::Provider::Package::Rpm, "remove" do + before(:each) do + @node = mock("Chef::Node", :null_object => true) + @new_resource = mock("Chef::Resource::Package", + :null_object => true, + :name => "emacs", + :version => nil, + :package_name => "emacs", + :updated => nil + ) + @provider = Chef::Provider::Package::Rpm.new(@node, @new_resource) + end + + it "should run rpm -e to remove the package" do + @provider.should_receive(:run_command).with({ + :command => "rpm -e emacs" + }) + @provider.remove_package("emacs", "21.4-20.el5") + end +end
\ No newline at end of file diff --git a/chef/spec/unit/provider/service/freebsd_service_spec.rb b/chef/spec/unit/provider/service/freebsd_service_spec.rb index 660ed67bb1..fa59cb6b55 100644 --- a/chef/spec/unit/provider/service/freebsd_service_spec.rb +++ b/chef/spec/unit/provider/service/freebsd_service_spec.rb @@ -188,22 +188,27 @@ describe Chef::Provider::Service::Freebsd, "enable_service" do @provider = Chef::Provider::Service::Freebsd.new(@node, @new_resource) Chef::Resource::Service.stub!(:new).and_return(@current_resource) - - @lines = mock("lines") - @lines.stub!(:readlines).and_return([ "apache22_enable=\"NO\"" ] ) - @lines.stub!(:close).and_return(true) - ::File.stub!(:open).and_return(@lines) + @provider.stub!(:service_enable_variable_name).and_return("apache22_enable") @provider.current_resource = @current_resource end it "should should enable the service if it is not enabled" do @current_resource.stub!(:enabled).and_return(false) - @lines.should_receive(:puts).with("apache22_enable=\"YES\"") + @provider.should_receive(:read_rc_conf).and_return([ "foo", "apache22_enable=\"NO\"", "bar" ]) + @provider.should_receive(:write_rc_conf).with(["foo", "bar", "apache22_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", "apache22_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 @@ -229,22 +234,20 @@ describe Chef::Provider::Service::Freebsd, "disable_service" do @provider = Chef::Provider::Service::Freebsd.new(@node, @new_resource) Chef::Resource::Service.stub!(:new).and_return(@current_resource) - - @lines = mock("lines") - @lines.stub!(:readlines).and_return( [ "apache22_enable=\"YES\"" ] ) - @lines.stub!(:close).and_return(true) - ::File.stub!(:open).and_return(@lines) + @provider.stub!(:service_enable_variable_name).and_return("apache22_enable") @provider.current_resource = @current_resource end it "should should disable the service if it is not disabled" do @current_resource.stub!(:enabled).and_return(true) - @lines.should_receive(:puts).with("apache22_enable=\"NO\"") + @provider.should_receive(:read_rc_conf).and_return([ "foo", "apache22_enable=\"YES\"", "bar" ]) + @provider.should_receive(:write_rc_conf).with(["foo", "bar", "apache22_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 diff --git a/chef/spec/unit/recipe_spec.rb b/chef/spec/unit/recipe_spec.rb index e0811647b2..60e95b724a 100644 --- a/chef/spec/unit/recipe_spec.rb +++ b/chef/spec/unit/recipe_spec.rb @@ -42,6 +42,14 @@ describe Chef::Recipe do 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 { || } }.should raise_error(NameError) diff --git a/chef/spec/unit/resource/cron_spec.rb b/chef/spec/unit/resource/cron_spec.rb index 0ff836d23d..28152342b1 100644 --- a/chef/spec/unit/resource/cron_spec.rb +++ b/chef/spec/unit/resource/cron_spec.rb @@ -119,4 +119,10 @@ describe Chef::Resource::Cron do 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 end diff --git a/chef/spec/unit/resource/mount_spec.rb b/chef/spec/unit/resource/mount_spec.rb new file mode 100644 index 0000000000..9886fb47ae --- /dev/null +++ b/chef/spec/unit/resource/mount_spec.rb @@ -0,0 +1,138 @@ +# +# Author:: Joshua Timberman (<joshua@opscode.com>) +# 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 File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "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 + +end diff --git a/chef/spec/unit/rest_spec.rb b/chef/spec/unit/rest_spec.rb index 525d17e148..8e789426ca 100644 --- a/chef/spec/unit/rest_spec.rb +++ b/chef/spec/unit/rest_spec.rb @@ -256,10 +256,19 @@ describe Chef::REST, "run_request method" do @http_response_mock.stub!(:[]).with('location').and_return(@url_mock.path) lambda { do_run_request(method=:GET, data=false, limit=1) }.should raise_error(ArgumentError) end + + it "should call run_request again on a Permanent Redirect response" do + @http_response_mock.stub!(:kind_of?).with(Net::HTTPSuccess).and_return(false) + @http_response_mock.stub!(:kind_of?).with(Net::HTTPFound).and_return(false) + @http_response_mock.stub!(:kind_of?).with(Net::HTTPMovedPermanently).and_return(true) + @http_response_mock.stub!(:[]).with('location').and_return(@url_mock.path) + lambda { do_run_request(method=:GET, data=false, limit=1) }.should raise_error(ArgumentError) + end it "should raise an exception on an unsuccessful request" do @http_response_mock.stub!(:kind_of?).with(Net::HTTPSuccess).and_return(false) @http_response_mock.stub!(:kind_of?).with(Net::HTTPFound).and_return(false) + @http_response_mock.stub!(:kind_of?).with(Net::HTTPMovedPermanently).and_return(false) @http_response_mock.should_receive(:error!) do_run_request end diff --git a/features/data/cookbooks/transfer_remote_files/recipes/transfer_a_file_from_a_specific_cookbook.rb b/features/data/cookbooks/transfer_remote_files/recipes/transfer_a_file_from_a_specific_cookbook.rb new file mode 100644 index 0000000000..1d2159f853 --- /dev/null +++ b/features/data/cookbooks/transfer_remote_files/recipes/transfer_a_file_from_a_specific_cookbook.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: transfer_remote_files +# Recipe:: default +# +# Copyright 2009, Opscode +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +transfer_cookbook "from_definition.txt" diff --git a/features/data/cookbooks/transfer_remote_files_definition/definitions/transfer.rb b/features/data/cookbooks/transfer_remote_files_definition/definitions/transfer.rb new file mode 100644 index 0000000000..6784c2e765 --- /dev/null +++ b/features/data/cookbooks/transfer_remote_files_definition/definitions/transfer.rb @@ -0,0 +1,6 @@ +define :transfer_cookbook do + remote_file "#{node[:tmpdir]}/#{params[:name]}" do + source "easy.txt" + cookbook "transfer_remote_files_definition" + end +end
\ No newline at end of file diff --git a/features/data/cookbooks/transfer_remote_files_definition/files/default/easy.txt b/features/data/cookbooks/transfer_remote_files_definition/files/default/easy.txt new file mode 100644 index 0000000000..ba56156ef3 --- /dev/null +++ b/features/data/cookbooks/transfer_remote_files_definition/files/default/easy.txt @@ -0,0 +1 @@ +easy like saturday morning
\ No newline at end of file diff --git a/features/transfer_remote_files.feature b/features/transfer_remote_files.feature index e75f582cdf..541cf9b4c9 100644 --- a/features/transfer_remote_files.feature +++ b/features/transfer_remote_files.feature @@ -39,3 +39,10 @@ Feature: Transfer Remote Files When I run the chef-client Then the run should exit '0' And a file named 'host_specific.txt' should be from the 'platform' specific directory + + Scenario: Transfer a file from a specific cookbook + Given a validated node + And it includes the recipe 'transfer_remote_files::transfer_a_file_from_a_specific_cookbook' + When I run the chef-client + Then the run should exit '0' + And a file named 'from_definition.txt' should contain 'easy like saturday morning'
\ No newline at end of file |