From 23186f0338ec248d930c85db08cc997bca42525b Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 22 May 2002 18:44:01 +0000 Subject: [PATCH] bind export, editing zones, deleting unaudited domains, mmm --- FS/FS/domain_record.pm | 129 +++++++++++++++++++++++++++++- FS/FS/part_export.pm | 11 +-- FS/FS/svc_domain.pm | 51 +++++++++++- bin/bind.export | 38 ++++++++- httemplate/edit/process/domain_record.cgi | 31 +++++++ httemplate/misc/cancel-unaudited.cgi | 11 ++- httemplate/misc/delete-domain_record.cgi | 15 ++++ httemplate/misc/delete-part_export.cgi | 2 +- httemplate/view/svc_domain.cgi | 31 +++++-- 9 files changed, 295 insertions(+), 24 deletions(-) create mode 100755 httemplate/edit/process/domain_record.cgi create mode 100755 httemplate/misc/delete-domain_record.cgi diff --git a/FS/FS/domain_record.pm b/FS/FS/domain_record.pm index 6f4dd0287..44e70ade1 100644 --- a/FS/FS/domain_record.pm +++ b/FS/FS/domain_record.pm @@ -3,7 +3,7 @@ package FS::domain_record; use strict; use vars qw( @ISA ); #use FS::Record qw( qsearch qsearchs ); -use FS::Record qw( qsearchs ); +use FS::Record qw( qsearchs dbh ); use FS::svc_domain; @ISA = qw(FS::Record); @@ -71,12 +71,80 @@ otherwise returns false. =cut +sub insert { + my $self = shift; + + local $SIG{HUP} = 'IGNORE'; + local $SIG{INT} = 'IGNORE'; + local $SIG{QUIT} = 'IGNORE'; + local $SIG{TERM} = 'IGNORE'; + local $SIG{TSTP} = 'IGNORE'; + local $SIG{PIPE} = 'IGNORE'; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + my $error = $self->SUPER::insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + unless ( $self->rectype =~ /^(SOA|_mstr)$/ ) { + my $error = $self->increment_serial; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + + ''; + +} + =item delete Delete this record from the database. =cut +sub delete { + my $self = shift; + + local $SIG{HUP} = 'IGNORE'; + local $SIG{INT} = 'IGNORE'; + local $SIG{QUIT} = 'IGNORE'; + local $SIG{TERM} = 'IGNORE'; + local $SIG{TSTP} = 'IGNORE'; + local $SIG{PIPE} = 'IGNORE'; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + my $error = $self->SUPER::delete; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + unless ( $self->rectype =~ /^(SOA|_mstr)$/ ) { + my $error = $self->increment_serial; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + + ''; + +} + =item replace OLD_RECORD Replaces the OLD_RECORD with this one in the database. If there is an error, @@ -84,6 +152,40 @@ returns the error, otherwise returns false. =cut +sub replace { + my $self = shift; + + local $SIG{HUP} = 'IGNORE'; + local $SIG{INT} = 'IGNORE'; + local $SIG{QUIT} = 'IGNORE'; + local $SIG{TERM} = 'IGNORE'; + local $SIG{TSTP} = 'IGNORE'; + local $SIG{PIPE} = 'IGNORE'; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + my $error = $self->SUPER::replace(@_); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + unless ( $self->rectype eq 'SOA' ) { + my $error = $self->increment_serial; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + + ''; + +} + =item check Checks all fields to make sure this is a valid example. If there is @@ -158,11 +260,34 @@ sub check { ''; #no error } +=item increment_serial + +=cut + +sub increment_serial { + my $self = shift; + + my $soa = qsearchs('domain_record', { + svcnum => $self->svcnum, + reczone => '@', #or full domain ? + recaf => 'IN', + rectype => 'SOA', + } ) or return "soa record not found; can't increment serial"; + + my $data = $soa->recdata; + $data =~ s/(\(\D*)(\d+)/$1.($2+1)/e; #well, it works. + + my %hash = $soa->hash; + $hash{recdata} = $data; + my $new = new FS::domain_record \%hash; + $new->replace($soa); +} + =back =head1 VERSION -$Id: domain_record.pm,v 1.7 2002-04-20 11:57:35 ivan Exp $ +$Id: domain_record.pm,v 1.8 2002-05-22 18:44:01 ivan Exp $ =head1 BUGS diff --git a/FS/FS/part_export.pm b/FS/FS/part_export.pm index 94b819d13..8a7ac8bf9 100644 --- a/FS/FS/part_export.pm +++ b/FS/FS/part_export.pm @@ -141,7 +141,7 @@ sub insert { ''; -}; +} =item delete @@ -361,7 +361,8 @@ sub option { Reblesses the object into the FS::part_export::EXPORTTYPE class, where EXPORTTYPE is the object's I field. There should be better docs -on how to create new exports, but until then, see L. +on how to create new exports (and they should live in their own files and be +autoloaded-on-demand), but until then, see L. =cut @@ -369,7 +370,7 @@ sub rebless { my $self = shift; my $exporttype = $self->exporttype; my $class = ref($self). "::$exporttype"; - eval "use $class;" or die $@; + eval "use $class;"; bless($self, $class); } @@ -617,13 +618,13 @@ tie my %bind_slave_options, 'Tie::IxHash', 'bind' => { 'desc' =>'Batch export to BIND named', 'options' => \%bind_options, - 'notes' => 'bind export notes', + 'notes' => 'bind export notes File::Rsync dependancy, run bind.export', }, 'bind_slave' => { 'desc' =>'Batch export to slave BIND named', 'options' => \%bind_slave_options, - 'notes' => 'bind export notes (secondary munge)', + 'notes' => 'bind export notes (secondary munge) File::Rsync dependancy, run bind.export', }, diff --git a/FS/FS/svc_domain.pm b/FS/FS/svc_domain.pm index 3dea7050f..a9a2fd0eb 100644 --- a/FS/FS/svc_domain.pm +++ b/FS/FS/svc_domain.pm @@ -255,10 +255,33 @@ sub delete { if defined( $FS::Record::dbdef->table('svc_acct_sm') ) && qsearch('svc_acct_sm', { 'domsvc' => $self->svcnum } ); - return "Can't delete a domain with (domain_record) zone entries!" - if qsearch('domain_record', { 'svcnum' => $self->svcnum } ); + #return "Can't delete a domain with (domain_record) zone entries!" + # if qsearch('domain_record', { 'svcnum' => $self->svcnum } ); - $self->SUPER::delete; + local $SIG{HUP} = 'IGNORE'; + local $SIG{INT} = 'IGNORE'; + local $SIG{QUIT} = 'IGNORE'; + local $SIG{TERM} = 'IGNORE'; + local $SIG{TSTP} = 'IGNORE'; + local $SIG{PIPE} = 'IGNORE'; + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + my $error = $self->SUPER::delete; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + foreach my $domain_record ( reverse $self->domain_record ) { + my $error = $domain_record->delete; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } } =item replace OLD_RECORD @@ -369,6 +392,26 @@ sub check { } +=item domain_record + +=cut + +sub domain_record { + my $self = shift; + + my %order = ( + SOA => 1, + NS => 2, + MX => 3, + CNAME => 4, + A => 5, + ); + + sort { $order{$a->rectype} <=> $order{$b->rectype} } + qsearch('domain_record', { svcnum => $self->svcnum } ); + +} + =item whois Returns the Net::Whois::Domain object (see L) for this domain, or @@ -407,7 +450,7 @@ sub submit_internic { =head1 VERSION -$Id: svc_domain.pm,v 1.28 2002-05-18 09:51:30 ivan Exp $ +$Id: svc_domain.pm,v 1.29 2002-05-22 18:44:01 ivan Exp $ =head1 BUGS diff --git a/bin/bind.export b/bin/bind.export index 8d6f4e339..d49b3cf64 100755 --- a/bin/bind.export +++ b/bin/bind.export @@ -2,6 +2,8 @@ use strict; use File::Path; +use File::Rsync; +use Net::SSH qw(ssh); use FS::UID qw(adminsuidsetup datasrc); use FS::Record qw(qsearch qsearchs); use FS::part_export; @@ -18,9 +20,15 @@ mkdir $spooldir unless -d $spooldir; my @exports = qsearch('part_export', { 'exporttype' => 'bind' } ); my @sexports = qsearch('part_export', { 'exporttype' => 'bind_slave' } ); +my $rsync = File::Rsync->new({ + rsh => 'ssh', +# dry_run => 1, +}); + foreach my $export ( @exports ) { - my $prefix = "$spooldir/". $export->machine; + my $machine = $export->machine; + my $prefix = "$spooldir/$machine"; #prevent old domain files from piling up #rmtree "$prefix" or die "can't rmtree $prefix.db: $!"; @@ -96,12 +104,30 @@ END } + $rsync->exec( { + src => "$prefix/", + recursive => 1, + dest => "root\@$machine:$zonepath/", + exclude => [qw( *.import named.conf.HEADER named.conf )], + } ) or die "rsync to $machine failed: ". join(" / ", $rsync->err); + # warn $rsync->out; + + $rsync->exec( { + src => "$prefix/named.conf", + dest => "root\@$machine:". $export->option('named_conf'), + } ) or die "rsync to $machine failed: ". join(" / ", $rsync->err); +# warn $rsync->out; + + ssh("root\@$machine", 'ndc reload'); + } + close NAMED_CONF; foreach my $sexport ( @sexports ) { #false laziness with above - my $prefix = "$spooldir/". $sexport->machine; + my $machine = $sexport->machine; + my $prefix = "$spooldir/$machine"; #prevent old domain files from piling up #rmtree "$prefix" or die "can't rmtree $prefix.db: $!"; @@ -137,6 +163,14 @@ END } + $rsync->exec( { + src => "$prefix/named.conf", + dest => "root\@$machine:". $sexport->option('named_conf'), + } ) or die "rsync to $machine failed: ". join(" / ", $rsync->err); +# warn $rsync->out; + + ssh("root\@$machine", 'ndc reload'); + } close NAMED_CONF; diff --git a/httemplate/edit/process/domain_record.cgi b/httemplate/edit/process/domain_record.cgi new file mode 100755 index 000000000..8fb0368f6 --- /dev/null +++ b/httemplate/edit/process/domain_record.cgi @@ -0,0 +1,31 @@ +<% + +my $recnum = $cgi->param('recnum'); + +my $old = qsearchs('agent',{'recnum'=>$recnum}) if $recnum; + +my $new = new FS::domain_record ( { + map { + $_, scalar($cgi->param($_)); + } fields('domain_record') +} ); + +my $error; +if ( $recnum ) { + $error=$new->replace($old); +} else { + $error=$new->insert; + $recnum=$new->getfield('recnum'); +} + +if ( $error ) { +# $cgi->param('error', $error); +# print $cgi->redirect(popurl(2). "agent.cgi?". $cgi->query_string ); + #no edit screen to send them back to + eidiot($error); +} else { + my $svcnum = $new->svcnum; + print $cgi->redirect(popurl(3). "view/svc_domain.cgi?$svcnum"); +} + +%> diff --git a/httemplate/misc/cancel-unaudited.cgi b/httemplate/misc/cancel-unaudited.cgi index ecfaef29f..f1fb15341 100755 --- a/httemplate/misc/cancel-unaudited.cgi +++ b/httemplate/misc/cancel-unaudited.cgi @@ -7,15 +7,18 @@ my($query) = $cgi->keywords; $query =~ /^(\d+)$/; my $svcnum = $1; -my $svc_acct = qsearchs('svc_acct',{'svcnum'=>$svcnum}); -die "Unknown svcnum!" unless $svc_acct; +#my $svc_acct = qsearchs('svc_acct',{'svcnum'=>$svcnum}); +#die "Unknown svcnum!" unless $svc_acct; my $cust_svc = qsearchs('cust_svc',{'svcnum'=>$svcnum}); +die "Unknown svcnum!" unless $cust_svc; &eidiot(qq!This account has already been audited. Cancel the package instead.!) if $cust_svc->pkgnum ne '' && $cust_svc->pkgnum ne '0'; +my $svc_x = $cust_svc->svc_x; + local $SIG{HUP} = 'IGNORE'; local $SIG{INT} = 'IGNORE'; local $SIG{QUIT} = 'IGNORE'; @@ -24,8 +27,8 @@ local $SIG{TSTP} = 'IGNORE'; local $FS::UID::AutoCommit = 0; -my $error = $svc_acct->cancel; -$error ||= $svc_acct->delete; +my $error = $svc_x->cancel; +$error ||= $svc_x->delete; $error ||= $cust_svc->delete; if ( $error ) { diff --git a/httemplate/misc/delete-domain_record.cgi b/httemplate/misc/delete-domain_record.cgi new file mode 100755 index 000000000..dcc2d5022 --- /dev/null +++ b/httemplate/misc/delete-domain_record.cgi @@ -0,0 +1,15 @@ +<% + +#untaint recnum +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/ || die "Illegal recnum"; +my $recnum = $1; + +my $domain_record = qsearchs('domain_record',{'recnum'=>$recnum}); + +my $error = $domain_record->delete; +eidiot($error) if $error; + +print $cgi->redirect($p. "view/svc_domain.cgi?". $domain_record->svcnum); + +%> diff --git a/httemplate/misc/delete-part_export.cgi b/httemplate/misc/delete-part_export.cgi index 34ef06b96..7c4ab8b9d 100755 --- a/httemplate/misc/delete-part_export.cgi +++ b/httemplate/misc/delete-part_export.cgi @@ -1,6 +1,6 @@ <% -#untaint paynum +#untaint exportnum my($query) = $cgi->keywords; $query =~ /^(\d+)$/ || die "Illegal exportnum"; my $exportnum = $1; diff --git a/httemplate/view/svc_domain.cgi b/httemplate/view/svc_domain.cgi index 61194a26d..28214f04e 100755 --- a/httemplate/view/svc_domain.cgi +++ b/httemplate/view/svc_domain.cgi @@ -35,7 +35,7 @@ print header('Domain View', menubar( ? ( "View this package (#$pkgnum)" => "${p}view/cust_pkg.cgi?$pkgnum", "View this customer (#$custnum)" => "${p}view/cust_main.cgi?$custnum", ) - : ( "Cancel this (unaudited) account" => + : ( "Cancel this (unaudited) domain" => "${p}misc/cancel-unaudited.cgi?$svcnum" ) ), "Main menu" => $p, @@ -46,17 +46,36 @@ print header('Domain View', menubar( qq!
Catch all email (change):!, $email ? "$email." : "(none)", qq!

View whois information.!, - '

', ntable("",2), + '

', + '', + ntable("",2), 'ZoneTypeData', ; -foreach my $domain_record ( qsearch('domain_record', { svcnum => $svcnum } ) ) { + +foreach my $domain_record ( $svc_domain->domain_record ) { print ''. $domain_record->reczone. ''. ''. $domain_record->recaf. ' '. $domain_record->rectype. ''. - ''. $domain_record->recdata. ''; + ''. $domain_record->recdata; + print qq! (delete)! + unless $domain_record->rectype eq 'SOA'; + print ''; } -print ''. - '
'. joblisting({'svcnum'=>$svcnum}, 1). +print '
'. + qq!
!. + qq!!. + ' '. + 'IN '. + ''. + ' '. + '

'. joblisting({'svcnum'=>$svcnum}, 1). ''; %> -- 2.11.0