module ASF

The ASF module contains a set of classes which encapsulate access to a number of data sources such as LDAP, ICLAs, auth lists, etc. This code originally was developed as a part of separate tools and was later refactored out into a common library. Some of the older tools don't fully make use of this refactoring.

Constants

ETCLDAP

Directory where ldap.conf resides. Differs based on operating system.

Public Class Methods

committers() click to toggle source

Obtain a list of committers from LDAP cn=committers,ou=groups,dc=apache,dc=org

# File lib/whimsy/asf/ldap.rb, line 376
def self.committers
  weakref(:committers) {Group.find('committers').members}
end
dereference_weakref(object, attr, &block) click to toggle source

safely dereference a weakref array attribute. Block provided is used when reference is not set or has been reclaimed.

# File lib/whimsy/asf/ldap.rb, line 349
def self.dereference_weakref(object, attr, &block)
  attr = "@#{attr}"
  value = object.instance_variable_get(attr) || block.call
  value[0..-1]
rescue WeakRef::RefError
  value = block.call
ensure
  if not value or RUBY_VERSION.start_with? '1'
    object.instance_variable_set(attr, value)
  elsif value and not value.instance_of? WeakRef
    object.instance_variable_set(attr, WeakRef.new(value))
  end
end
init_ldap(reset = false) click to toggle source

public entry point for establishing a connection safely

# File lib/whimsy/asf/ldap.rb, line 281
def self.init_ldap(reset = false)
  ASF::LDAP::CONNECT_LOCK.synchronize do
    @ldap = nil if reset
    @ldap ||= ASF::LDAP.connect(!reset)
  end
end
ldap() click to toggle source

Returns existing LDAP connection, creating one if necessary.

# File lib/whimsy/asf/ldap.rb, line 296
def self.ldap
  @ldap || self.init_ldap
end
library_gitinfo() click to toggle source

Last commit in this clone, and the date and time of that commit.

# File lib/whimsy/asf.rb, line 35
def self.library_gitinfo
  return @info if @info
  @info = %x`git show --format="%h  %ci"  -s HEAD`.strip
end
library_mtime() click to toggle source

Last modified time of any file in the entire source tree.

# File lib/whimsy/asf.rb, line 27
def self.library_mtime
  parent_dir = File.dirname(File.expand_path(__FILE__))
  sources = Dir.glob("#{parent_dir}/**/*")
  times = sources.map {|source| File.mtime(source.untaint)}
  times.max.gmtime
end
members() click to toggle source

Obtain a list of members from LDAP cn=member,ou=groups,dc=apache,dc=org Note: includes some non-ASF member infrastructure contractors

# File lib/whimsy/asf/ldap.rb, line 383
def self.members
  weakref(:members) {Group.find('member').members}
end
pmc_chairs() click to toggle source

Obtain a list of PMC chairs from LDAP cn=pmc-chairs,ou=groups,ou=services,dc=apache,dc=org

# File lib/whimsy/asf/ldap.rb, line 370
def self.pmc_chairs
  weakref(:pmc_chairs) {Service.find('pmc-chairs').members}
end
search_archive_by_id(id) click to toggle source

Search archive for historical records of people who were committers but never submitted an ICLA (some of which are still ASF members or members of a PMC).

# File lib/whimsy/asf/icla.rb, line 220
def self.search_archive_by_id(id)
  archive = ASF::SVN['private/foundation/officers/historic']
  name = JSON.parse(File.read("#{archive}/committers.json"))[id]
  name = id if name and name.empty?
  name
end
search_one(base, filter, attrs=nil) click to toggle source

search with a scope of one, with automatic retry/failover

# File lib/whimsy/asf/ldap.rb, line 301
def self.search_one(base, filter, attrs=nil)
  self.search_scope(::LDAP::LDAP_SCOPE_ONELEVEL, base, filter, attrs)
end
search_scope(scope, base, filter, attrs=nil) click to toggle source

search with a specified scope, with automatic retry/failover

# File lib/whimsy/asf/ldap.rb, line 311
def self.search_scope(scope, base, filter, attrs=nil)

  # Dummy command, used for logging purposes only
  sname = %w(base one sub children)[scope] rescue scope
  cmd = "ldapsearch -x -LLL -b #{base} -s #{sname} #{filter} " +
    "#{[attrs].flatten.join(' ')}"

  # try once per host, with a minimum of two tries
  attempts_left = [ASF::LDAP.hosts.length, 2].max
  begin
    attempts_left -= 1
    init_ldap unless @ldap
    return [] unless @ldap

    target = @ldap.get_option(::LDAP::LDAP_OPT_HOST_NAME) rescue '?'
    Wunderbar.info "[#{target}] #{cmd}"

    result = @ldap.search2(base, scope, filter, attrs)
  rescue Exception => re
    if attempts_left <= 0
      Wunderbar.error "[#{target}] => #{re.inspect} for #{cmd}"
      raise
    else
      Wunderbar.warn "[#{target}] => #{re.inspect} for #{cmd}, retrying ..."
      @ldap.unbind if @ldap.bound? rescue nil
      @ldap = nil # force new connection
      sleep 1
      retry
    end
  end

  result.map! {|hash| hash[attrs]} if String === attrs

  result.compact
end
search_subtree(base, filter, attrs=nil) click to toggle source

search with a scope of subtree, with automatic retry/failover

# File lib/whimsy/asf/ldap.rb, line 306
def self.search_subtree(base, filter, attrs=nil)
  self.search_scope(::LDAP::LDAP_SCOPE_SUBTREE, base, filter, attrs)
end
weakref(attr, &block) click to toggle source

shortcut for dereference weakref

# File lib/whimsy/asf/ldap.rb, line 364
def self.weakref(attr, &block)
  self.dereference_weakref(self, attr, &block)
end