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.

Access to documents/* (except member_apps)

Constants

ETCLDAP

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

Public Class Methods

committerids() click to toggle source

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

# File lib/whimsy/asf/ldap.rb, line 401
def self.committerids
  weakref(:committerids) {RoleGroup.find('committers').memberids}
end
committers() click to toggle source

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

# File lib/whimsy/asf/ldap.rb, line 395
def self.committers
  weakref(:committers) {RoleGroup.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. N.B. dereference_weakref(object, :XYZ, block) stores the reference in @XYZ

# File lib/whimsy/asf/ldap.rb, line 352
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

  # keep track of which weak references are saved
  @@weakrefs << attr if object == self
end
flush_weakrefs() click to toggle source
# File lib/whimsy/asf/ldap.rb, line 369
def self.flush_weakrefs
  @@weakrefs.each do |attr|
    self.remove_instance_variable(attr)
  end

  @@weakrefs.clear

  # run garbage collection
  GC.start
end
init_ldap(reset = false, hosts = nil) click to toggle source

public entry point for establishing a connection safely

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

Returns existing LDAP connection, creating one if necessary.

# File lib/whimsy/asf/ldap.rb, line 298
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 = `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
memberids() click to toggle source

Obtain a list of memberids from LDAP cn=member,ou=groups,dc=apache,dc=org Note: includes some non-ASF member infrastructure contractors TODO: convert to RoleGroup at some point?

# File lib/whimsy/asf/ldap.rb, line 417
def self.memberids
  weakref(:memberids) {Group.find('member').memberids}
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 TODO: convert to RoleGroup at some point?

# File lib/whimsy/asf/ldap.rb, line 409
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 Note: this list may include non-PMC VPs.

# File lib/whimsy/asf/ldap.rb, line 389
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 264
def self.search_archive_by_id(id)
  archive = ASF::SVN['officers_historic']
  name = JSON.parse(File.read(File.join(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 303
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 313
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 308
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 N.B. weakref(:XYZ) stores the reference in @XYZ

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