require 'chef/provisioning/machine/basic_machine' require 'digest' class Chef module Provisioning class Machine class UnixMachine < BasicMachine def initialize(machine_spec, transport, convergence_strategy) super @tmp_dir = '/tmp' end # Options include: # # command_prefix - prefix to put in front of any command, e.g. sudo attr_reader :options # Delete file def delete_file(action_handler, path) if file_exists?(path) action_handler.perform_action "delete file #{path} on #{machine_spec.name}" do transport.execute("rm -f #{path}").error! end end end def is_directory?(path) result = transport.execute("stat -c '%F' #{path}", :read_only => true) return nil if result.exitstatus != 0 result.stdout.chomp == 'directory' end # Return true or false depending on whether file exists def file_exists?(path) result = transport.execute("ls -d #{path}", :read_only => true) result.exitstatus == 0 && result.stdout != '' end def files_different?(path, local_path, content=nil) if !file_exists?(path) || (local_path && !File.exists?(local_path)) return true end # Get remote checksum of file result = transport.execute("md5sum -b #{path}", :read_only => true) unless result.exitstatus == 0 result = transport.execute("md5 -r #{path}", :read_only => true) end result.error! remote_sum = result.stdout.split(' ')[0] digest = Digest::MD5.new if content digest.update(content) else File.open(local_path, 'rb') do |io| while (buf = io.read(4096)) && buf.length > 0 digest.update(buf) end end end remote_sum != digest.hexdigest end def create_dir(action_handler, path) if !file_exists?(path) action_handler.perform_action "create directory #{path} on #{machine_spec.name}" do transport.execute("mkdir -p #{path}").error! end end end # Set file attributes { mode, :owner, :group } def set_attributes(action_handler, path, attributes) if attributes[:mode] || attributes[:owner] || attributes[:group] current_attributes = get_attributes(path) if attributes[:mode] && current_attributes[:mode].to_i != attributes[:mode].to_i action_handler.perform_action "change mode of #{path} on #{machine_spec.name} from #{current_attributes[:mode].to_i} to #{attributes[:mode].to_i}" do transport.execute("chmod #{attributes[:mode].to_i} #{path}").error! end end if attributes[:owner] && current_attributes[:owner] != attributes[:owner] action_handler.perform_action "change group of #{path} on #{machine_spec.name} from #{current_attributes[:owner]} to #{attributes[:owner]}" do transport.execute("chown #{attributes[:owner]} #{path}").error! end end if attributes[:group] && current_attributes[:group] != attributes[:group] action_handler.perform_action "change group of #{path} on #{machine_spec.name} from #{current_attributes[:group]} to #{attributes[:group]}" do transport.execute("chgrp #{attributes[:group]} #{path}").error! end end end end # Get file attributes { :mode, :owner, :group } def get_attributes(path) result = transport.execute("stat -c '%a %U %G %n' #{path}", :read_only => true) return nil if result.exitstatus != 0 file_info = result.stdout.split(/\s+/) if file_info.size <= 1 raise "#{path} does not exist in set_attributes()" end result = { :mode => file_info[0], :owner => file_info[1], :group => file_info[2] } end def dirname_on_machine(path) path.split('/')[0..-2].join('/') end end def detect_os(action_handler) # # Use detect.sh to detect the operating system of the remote machine # # TODO do this in terms of commands rather than writing a shell script self.write_file(action_handler, "#{@tmp_dir}/detect.sh", detect_sh) detected = self.execute_always("sh #{@tmp_dir}/detect.sh") if detected.exitstatus != 0 raise "detect.sh exited with nonzero exit status: #{detected.exitstatus}" end platform = nil platform_version = nil machine_architecture = nil detected.stdout.each_line do |line| if line =~ /^PLATFORM: (.+)/ platform = $1 elsif line =~ /^PLATFORM_VERSION: (.+)/ platform_version = $1 elsif line =~ /^MACHINE: (.+)/ machine_architecture = $1 end end [ platform, platform_version, machine_architecture ] end private def detect_sh result = < 5 platform_version=`uname -r | sed 's/.*-WR\([0-9]\+\).*/\1/'` fi fi if test "x$platform" = "x"; then echo "Unable to determine platform version!" report_bug exit 1 fi # Mangle $platform_version to pull the correct build # for various platforms major_version=`echo $platform_version | cut -d. -f1` case $platform in "el") platform_version=$major_version ;; "debian") case $major_version in "5") platform_version="6";; "6") platform_version="6";; "7") platform_version="6";; esac ;; "freebsd") platform_version=$major_version ;; "sles") platform_version=$major_version ;; "suse") platform_version=$major_version ;; esac if test "x$platform_version" = "x"; then echo "Unable to determine platform version!" report_bug exit 1 fi if test "x$platform" = "xsolaris2"; then # hack up the path on Solaris to find wget PATH=/usr/sfw/bin:$PATH export PATH fi echo "PLATFORM: $platform" echo "PLATFORM_VERSION: $platform_version" echo "MACHINE: $machine" EOM end end end end