Skip to content

Instantly share code, notes, and snippets.

@gondoi
Last active December 17, 2015 02:29
Show Gist options
  • Save gondoi/5536321 to your computer and use it in GitHub Desktop.
Save gondoi/5536321 to your computer and use it in GitHub Desktop.
lock_wait has been added as an option to the apt_package resource.
class File
def flocked? &block
flockstruct = [Fcntl::F_RDLCK, 0, 0, 0, 0].pack("ssqqi")
fcntl Fcntl::F_GETLK, flockstruct
status = flockstruct.unpack("ssqqi")[0]
case status
when Fcntl::F_UNLCK
return false
when Fcntl::F_WRLCK|Fcntl::F_RDLCK
return true
else
raise SystemCallError, status
end
end
alias_method "if_not_flocked", "flocked?"
end
require 'timeout'
require 'chef/provider/package'
require 'chef/mixin/command'
require 'chef/resource/package'
require 'chef/mixin/shell_out'
require 'chef/mixin/file'
class Chef
class Provider
class Package
class Apt < Chef::Provider::Package
...
def install_package(name, version)
package_name = "#{name}=#{version}"
package_name = name if @is_virtual_package
AptDB::Locks.wait_on_lock(@new_resource.lock_wait)
run_command_with_systems_locale(
:command => "apt-get -q -y#{expand_options(default_release_options)}#{expand_options(@new_resource.options)} install #{package_name}",
:environment => {
"DEBIAN_FRONTEND" => "noninteractive"
}
)
end
...
end
module AptDB
module Locks
#This function opens the file passed, and checks to see if it is locked
def self.is_locked? fname
f = File.new(fname)
if f.flocked?
f.close
return true
else
f.close
return false
end
end
#This function runs through possible apt lock files and checks for a current lock
def self.apt_locked?
lock_files = [
"/var/lib/dpkg/lock",
"/var/lock/aptitude",
"/var/cache/apt/archives/lock",
"/var/lib/apt/lists/lock"
]
lock_files.each do |f|
if File.exists?(f) and is_locked?(f)
return true
end
end
return false
end
#This function will ask if apt is locked and sleep
def self.wait_on_lock( timeout_sec = 60 )
begin
Timeout::timeout(timeout_sec) do
if apt_locked?
Chef::Log.warn("Apt DB is locked. Sleeping...")
while apt_locked?
sleep(5)
end
Chef::Log.info("Apt DB is free. Waking up.")
end
end
rescue
Chef::Application.fatal!("Apt has been locked for too long.", -10)
end
end
end
end
require 'chef/resource/package'
require 'chef/provider/package/apt'
class Chef
class Resource
class AptPackage < Chef::Resource::Package
def initialize(name, run_context=nil)
super
@resource_name = :apt_package
@provider = Chef::Provider::Package::Apt
@default_release = nil
@lock_wait = 300
end
def default_release(arg=nil)
set_or_return(
:default_release,
arg,
:kind_of => [ String ]
)
end
def lock_wait(arg=nil)
set_or_return(
:lock_wait,
arg,
:kind_of => [ Integer ]
)
end
end
end
end
Failures:
1) Chef::Provider::Package::Apt install_package should run apt-get install with the package name and version
Failure/Error: @provider.install_package("irssi", "0.8.12-7")
NoMethodError:
undefined method `lock_wait' for Chef::Resource::Package
# ./lib/chef/resource.rb:293:in `method_missing'
# ./lib/chef/provider/package/apt.rb:96:in `install_package'
# ./spec/unit/provider/package/apt_spec.rb:203:in `block (3 levels) in <top (required)>'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment