summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG29
-rw-r--r--NOTICE3
-rw-r--r--chef-server/NOTICE17
-rw-r--r--chef-server/Rakefile2
-rw-r--r--chef-server/chef-server.gemspec2
-rw-r--r--chef/NOTICE11
-rw-r--r--chef/Rakefile4
-rwxr-xr-xchef/bin/chef-client2
-rw-r--r--chef/chef.gemspec2
-rw-r--r--chef/lib/chef.rb2
-rw-r--r--chef/lib/chef/platform.rb1
-rw-r--r--chef/lib/chef/provider/mount.rb121
-rw-r--r--chef/lib/chef/provider/mount/mount.rb153
-rw-r--r--chef/lib/chef/provider/package/freebsd.rb74
-rw-r--r--chef/lib/chef/provider/package/rpm.rb92
-rw-r--r--chef/lib/chef/provider/service/freebsd.rb71
-rw-r--r--chef/lib/chef/recipe.rb17
-rw-r--r--chef/lib/chef/resource/cron.rb35
-rw-r--r--chef/lib/chef/resource/mount.rb125
-rw-r--r--chef/lib/chef/rest.rb3
-rw-r--r--chef/spec/lib/chef/resource/one_two_three_four.rb43
-rw-r--r--chef/spec/unit/provider/mount/mount_spec.rb478
-rw-r--r--chef/spec/unit/provider/mount_spec.rb263
-rw-r--r--chef/spec/unit/provider/package/freebsd_spec.rb68
-rw-r--r--chef/spec/unit/provider/package/rpm_spec.rb150
-rw-r--r--chef/spec/unit/provider/service/freebsd_service_spec.rb27
-rw-r--r--chef/spec/unit/recipe_spec.rb8
-rw-r--r--chef/spec/unit/resource/cron_spec.rb6
-rw-r--r--chef/spec/unit/resource/mount_spec.rb138
-rw-r--r--chef/spec/unit/rest_spec.rb9
-rw-r--r--features/data/cookbooks/transfer_remote_files/recipes/transfer_a_file_from_a_specific_cookbook.rb20
-rw-r--r--features/data/cookbooks/transfer_remote_files_definition/definitions/transfer.rb6
-rw-r--r--features/data/cookbooks/transfer_remote_files_definition/files/default/easy.txt1
-rw-r--r--features/transfer_remote_files.feature7
34 files changed, 1850 insertions, 140 deletions
diff --git a/CHANGELOG b/CHANGELOG
index b75b9a9e68..d9d9fa95ef 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -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/
diff --git a/NOTICE b/NOTICE
index 74f868edfc..d13bc839e4 100644
--- a/NOTICE
+++ b/NOTICE
@@ -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