Created
December 29, 2010 16:12
-
-
Save fapestniegd/758680 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/local/bin/perl | |
| # | |
| # We use /usr/local/bin/perl because cygwin installs in /usr/bin/perl and we want to | |
| # use ActiveState Perl on Windows. As a result, we have to symlink all others | |
| # links: | |
| # !compiled_on_cygwin:: | |
| # /usr/local/bin/perl -> /usr/bin/perl type=symbolic | |
| # | |
| use strict; | |
| # This is the LDAP module that makes all the dynamic stuff in cfengine work | |
| # determine this host's fqdn | |
| # determine this host's domain name | |
| # do a srv record lookup for ldap tcp 636 on this domain name | |
| # | |
| # if this host's fqdn is one of the returned records: | |
| # try to connect to self's fqdn for LDAP, | |
| # then try to connect to other records until one connects | |
| # if one is reached: | |
| # look up cn=hostname, ou=Hosts, dc=domain, dc=domain, dc=domain | |
| # and activate all classes in record and exit. | |
| # if record is not found, back-off and retry on next pass. | |
| # if none of the ldap servers can be reached, including oneself then assume localhost | |
| # is the first of it's kind and: | |
| # activate core_server, which will: | |
| # activate cfengine_server | |
| # (if debian) update /etc/apt/sources.list to use backports | |
| # (if debian) create /etc/apt/preferences to mask backports for !git | |
| # install git | |
| # install git2masterfiles | |
| # activate certificate_authority | |
| # using "secret" create caroot tree | |
| # using "secret" create gpg identity | |
| # activate ldap_server, which will: | |
| # add slapd.conf for self's domain name (determined earlier) if not exists | |
| # start slapd, | |
| # create self's host record if it doesn't exist, | |
| # define classes for self | |
| # setup and run all core services | |
| # | |
| # if no ldap servers are reachable and the fqdn is not in the _ldap._tcp srv list, | |
| # then take no action; Assume the host is disconnected from the core completely. | |
| # | |
| package Superstring; | |
| use Data::Dumper; | |
| sub new{ | |
| use Sys::Hostname; | |
| use Sys::Hostname::Long; | |
| use FileHandle; | |
| my $class = shift; | |
| my $construct = shift if @_; | |
| my $self = { }; | |
| bless ($self, $class); | |
| $self->{'cfg'}->{'fqdn'} = hostname_long(); | |
| $self->{'cfg'}->{'hostname'} = hostname(); | |
| $self->{'cfg'}->{'hostname'}=~s/\..*//g; | |
| $self->{'cfg'}->{'domain'} = $self->{'cfg'}->{'fqdn'}; | |
| $self->{'cfg'}->{'domain'} =~ s/^$self->{'cfg'}->{'hostname'}\.//; | |
| $self->{'cfg'}->{'base_dn'} = $self->{'cfg'}->{'domain'}; | |
| $self->{'cfg'}->{'base_dn'} =~ s/^/dc=/; | |
| $self->{'cfg'}->{'base_dn'} =~ s/\./,dc=/; | |
| if(-f "/usr/local/sbin/secret"){ | |
| my $sech = new FileHandle; | |
| if($sech->open("/usr/local/sbin/secret|")){ | |
| $self->{'cfg'}->{'secret'}=<$sech>; | |
| $sech->close; | |
| } | |
| } | |
| if($self->{'cfg'}->{'domain'} ne ""){ | |
| return $self; | |
| } | |
| return undef; | |
| } | |
| ################################################### | |
| # Get all the DNS records that could determine | |
| # what this host is supposed to be | |
| ################################################### | |
| sub get_dns_records(){ | |
| use Net::DNS; | |
| my $self = shift; | |
| my $res = Net::DNS::Resolver->new; | |
| my $query = $res->query("_ldap._tcp.".$self->{'cfg'}->{'domain'}, "SRV"); | |
| if ($query){ | |
| foreach my $rr (grep { $_->type eq 'SRV' } $query->answer) { | |
| push(@{ $self->{'cfg'}->{'ldap_servers'} },$rr->target); | |
| if($rr->target eq $self->{'cfg'}->{'fqdn'}){ | |
| push(@{ $self->{'cfclasses'} },"ldap_server"); | |
| } | |
| } | |
| }else{ | |
| push(@{ $self->{'cfclasses'} },'dns_errors'); | |
| warn "query failed: ", $res->errorstring, "\n"; | |
| } | |
| my $query = $res->query($self->{'cfg'}->{'domain'}, "NS"); | |
| if ($query){ | |
| foreach my $rr (grep { $_->type eq 'NS' } $query->answer) { | |
| my $nameserver=$rr->nsdname; | |
| my $res2 = Net::DNS::Resolver->new; | |
| my $subquery = $res2->query($nameserver, "A"); | |
| if ($subquery){ | |
| foreach my $rra (grep { $_->type eq 'A' } $subquery->answer) { | |
| push(@{ $self->{'cfg'}->{'dns'}->{'a'}->{$nameserver} },$rra->address); | |
| my $res3 = Net::DNS::Resolver->new; | |
| my $ptrquery = $res2->query($rra->address, "PTR"); | |
| if ($ptrquery){ | |
| foreach my $rrp (grep { $_->type eq 'PTR' } $ptrquery->answer) { | |
| push(@{ $self->{'cfg'}->{'dns'}->{'ptr'}->{$rra->address} },$rrp->ptrdname); | |
| if($rrp->ptrdname eq $self->{'cfg'}->{'fqdn'}){ | |
| push(@{ $self->{'cfclasses'} },"bind9_server"); | |
| } | |
| } | |
| }else{ | |
| push(@{ $self->{'cfclasses'} },'dns_errors'); | |
| warn "query failed: ", $res3->errorstring, "\n"; | |
| } | |
| } | |
| }else{ | |
| push(@{ $self->{'cfclasses'} },'dns_errors'); | |
| warn "query failed: ", $res2->errorstring, "\n"; | |
| } | |
| push(@{ $self->{'cfg'}->{'dns'}->{'ns'} },$rr->nsdname); | |
| if($rr->nsdname eq $self->{'cfg'}->{'fqdn'}){ | |
| push(@{ $self->{'cfclasses'} },"bind9_server"); | |
| } | |
| } | |
| }else{ | |
| warn "query failed: ", $res->errorstring, "\n"; | |
| } | |
| return $self; | |
| } | |
| sub add_classes(){ | |
| my $self=shift; | |
| foreach my $c (@_){ | |
| push(@{ $self->{'cfclasses'} }, $c); | |
| } | |
| return $self; | |
| } | |
| sub dumpclasses(){ | |
| my $self=shift; | |
| foreach my $c (@{ $self->{'cfclasses'} }){ | |
| print "+",$c,"\n"; | |
| } | |
| return $self; | |
| } | |
| sub dumpvariables(){ | |
| my $self=shift; | |
| foreach my $k (keys(%{ $self->{'variables'} })){ | |
| print "=",$k,"=",$self->{'variables'}->{$k},"\n"; | |
| } | |
| return $self; | |
| } | |
| sub ldap_servers{ | |
| my $self=shift; | |
| return $self->{'cfg'}->{'ldap_servers'} if defined $self->{'cfg'}->{'ldap_servers'}; | |
| return undef; | |
| } | |
| sub domain{ | |
| my $self=shift; | |
| return $self->{'cfg'}->{'domain'} if defined $self->{'cfg'}->{'domain'}; | |
| return undef; | |
| } | |
| sub base_hostname{ | |
| my $self=shift; | |
| return $self->{'cfg'}->{'hostname'} if defined $self->{'cfg'}->{'hostname'}; | |
| return undef; | |
| } | |
| sub fqdomain{ | |
| my $self=shift; | |
| return $self->{'cfg'}->{'fqdn'} if defined $self->{'cfg'}->{'fqdn'}; | |
| return undef; | |
| } | |
| ################################################### | |
| # Attempt to contact all the LDAP Servers | |
| # and get this hosts LDAP record | |
| ################################################### | |
| sub ldapsearch{ | |
| use Net::LDAP; | |
| my $self=shift; | |
| my $setup=shift; | |
| my $returnlist; | |
| my $ldap = Net::LDAP->new( $setup->{'host'}, timeout => 10) or warn "$@"; | |
| my $mesg; | |
| if($ldap){ | |
| if(defined($self->{'cfg'}->{'secret'})){ | |
| $mesg = $ldap->bind( | |
| "cn=$self->{'cfg'}->{'hostname'},ou=Hosts,$self->{'cfg'}->{'base_dn'}", | |
| password=> $self->{'cfg'}->{'secret'} | |
| ); | |
| }else{ | |
| $mesg = $ldap->bind; # an anonymous bind | |
| } | |
| $mesg = $ldap->search( base => $setup->{'basedn'},scope=>'base',filter => "($setup->{'search'})"); | |
| $mesg->code && warn $mesg->error; | |
| foreach my $entry ($mesg->entries) { push(@{$returnlist},$entry); } | |
| $mesg = $ldap->unbind; # take down session | |
| } | |
| return $returnlist; | |
| } | |
| sub host_ldap_record(){ | |
| my $self=shift; | |
| my $host=shift; | |
| my $basedn="cn=".$self->base_hostname().",ou=Hosts,dc=".join(",dc=",split(/\./,$self->domain())); | |
| my $searchdn="cn=".$self->base_hostname(); | |
| # loop through ldap_records and see if we are one of them... | |
| my $iamone=0; | |
| foreach my $ldap_server (@{$self->ldap_servers}){ | |
| if($self->{'cfg'}->{'fqdn'} eq $ldap_server){ $iamone=1; } | |
| } | |
| # first try to fetch the record from oneself | |
| if($iamone){ | |
| # get host record from our self | |
| print STDERR "Searching for $searchdn via ldap://".$self->fqdomain().":636\n"; | |
| $self->{'cfg'}->{'ldap'}->{'hostrecord'}=$self->ldapsearch({'host'=>$self->fqdomain(),'basedn'=>$basedn,'search'=>$searchdn}); | |
| } | |
| if(!defined( $self->{'cfg'}->{'ldap'}->{'hostrecord'} )){ | |
| foreach my $ldap_server (@{$self->ldap_servers}){ | |
| # We already tried self... | |
| next if(($self->{'cfg'}->{'fqdn'} eq $ldap_server)||(defined($self->{'cfg'}->{'ldap'}->{'hostrecord'}))); | |
| print STDERR "Searching for $searchdn via ldap://".$ldap_server.":636\n"; | |
| $self->{'cfg'}->{'ldap'}->{'hostrecord'}=$self->ldapsearch({'host'=>$ldap_server,'basedn'=>$basedn,'search'=>$searchdn}); | |
| if(defined($self->{'cfg'}->{'ldap'}->{'hostrecord'})){ print STDERR "$searchdn found.\n"; } | |
| } | |
| } | |
| if(($iamone eq 1)&&(!defined( $self->{'cfg'}->{'ldap'}->{'hostrecord'} ))){ | |
| $self->add_classes("core_server"); | |
| } | |
| return $self; | |
| } | |
| 1; | |
| my $ss = Superstring->new(); | |
| if($ss){ | |
| $ss->get_dns_records(); | |
| if(defined($ss->ldap_servers())){ | |
| $ss->host_ldap_record($ss->fqdomain()); | |
| foreach my $entry ( @{ $ss->{'cfg'}->{'ldap'}->{'hostrecord'} }){ | |
| foreach my $attr ( $entry->attributes ){ | |
| if($attr =~ /^configSet$/i){ | |
| $ss->add_classes($entry->get_value( $attr )); | |
| } | |
| if($attr =~ /^configBase$/i){ | |
| $ss->add_classes($entry->get_value( $attr )); | |
| } | |
| } | |
| } | |
| }else{ | |
| print "No ldap server SRV records found in DNS\n"; | |
| } | |
| binmode STDOUT; | |
| $ss->dumpclasses(); | |
| $ss->dumpvariables(); | |
| } | |
| #print Data::Dumper->Dump([$ss]); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment