class PagerDuty::ChefServer::SyncLock

Public Class Methods

new(lockfile, server_hostname, local_hostname, user, branch, force_lock = false) click to toggle source
# File lib/pagerduty/chef_server/synclock.rb, line 27
def initialize(lockfile, server_hostname, local_hostname, user, branch, force_lock = false)
  @lockfile = lockfile
  @server_hostname = server_hostname.include?('.') ? server_hostname.split('.')[0] : server_hostname
  @local_hostname = local_hostname
  @user = user
  @branch = branch
  @opts = parse_opts({ announce: true, lock: true, force: force_lock })
end

Public Instance Methods

lock(time = Time.now) click to toggle source

get lock

# File lib/pagerduty/chef_server/synclock.rb, line 37
def lock(time = Time.now)
  verify_lockable

  @f_lock = procure_lock if @opts[:lock] || @opts[:force]
end
unlock() click to toggle source

remove lock

# File lib/pagerduty/chef_server/synclock.rb, line 44
def unlock
  if @opts[:lock]
    Chef::Knife.ui.info 'removing lockfile'
    @f_lock.flock(File::LOCK_UN)
    @f_lock.close
    FileUtils.rm(@f_lock.path)
  end
end

Private Instance Methods

local_chef_server?() click to toggle source
# File lib/pagerduty/chef_server/synclock.rb, line 72
def local_chef_server?
  @local_hostname.include? 'chef'
end
parse_opts(options) click to toggle source
# File lib/pagerduty/chef_server/synclock.rb, line 66
def parse_opts(options)
  options[:announce] &&= false unless remote_chef_server?
  options[:lock] &&= false unless local_chef_server?
  options
end
procure_lock() click to toggle source
# File lib/pagerduty/chef_server/synclock.rb, line 80
def procure_lock
  Chef::Knife.ui.info 'trying to obtain exclusive lock...'

  # create a file handle for the lockfile -- create if it doesn't exist and
  # make it read/write
  lf = File.open(@lockfile, File::CREAT|File::RDWR, 0644)

  unless lf.flock(File::LOCK_NB|File::LOCK_EX)
    # if we fail to obtain the lock figure out who has lock and for
    # how long so we can display that information
    ld = JSON.parse(lf.read.strip)
    msg = if (ld['user'].strip == @user)
            "according to lockfile you've had lock for" \
            " #{Time.now.to_i - ld['ts']} second(s)."
          else
            "unable to get exclusive lock, currently held by" \
            " #{ld['user']} for #{Time.now.to_i - ld['ts']} second(s)" \
          end
    # close the file handle
    lf.close
    Chef::Knife.ui.fatal msg
    raise LockUnavailable, msg
  end
  # we could get lock, so write our information to the file
  lf.write(JSON.dump({ user: @user, ts: Time.now.to_i }))
  lf.flush
  Chef::Knife.ui.info 'lock obtained'
  lf
end
remote_chef_server?() click to toggle source
# File lib/pagerduty/chef_server/synclock.rb, line 76
def remote_chef_server?
  @server_hostname.include? 'chef'
end
verify_lockable() click to toggle source
# File lib/pagerduty/chef_server/synclock.rb, line 55
def verify_lockable
  unless local_chef_server? && @opts[:force]
    @opts[:lock] = false
    Chef::Knife.ui.warn(
      'Please be careful, this looks to be running on a system other than a chef server. '\
        'As such, there will be *no* locking. Hold on to your butts...'
    )
    sleep 5
  end
end