Commit Diff


commit - aacad1502bdc25fce80270271b31ead69c9c95b7
commit + adb27c97ca6881b235c352fdf9b9c723cf979564
blob - 75d6a2cd8392a418297e7d4e3d4c24a652381759
blob + fb082187e33ef3726cfa060c46263e39c2672aea
--- bin/configNow.pl
+++ bin/configNow.pl
@@ -7,22 +7,23 @@ use IRCNOW::ConfigNow;
 
 use File::Basename;
 use File::Path qw(make_path);
-my $shellname = shift || 'bnsnet';
-my $username = shift || 'izzyb';
+my $shellname = shift || 'blacklock';
+my @users = qw( izzyb nathan ashley );
 my $domain = 'user.planetofnix.com';
 my %config=(
 	type=>'shell',
 	shellname => $shellname,
-	username => $username,
+	users => \@users,
 	gitAuthor => $shellname,
 	gitEmail => $shellname . "@" . $domain,
 	gitWorkDir => './configNow',
-	#	configNow => './configNow',
 	ipv4 => '38.87.162.191',
 	ipv6 => '2602:fccf:1:1191::',
 	domain => $domain,
 );
 my $shellConfig = new IRCNOW::ConfigNow( %config );
+#use Data::Dumper;
+#die  Dumper($shellConfig->{lists});
 
 if ($shellConfig->repo_ready()) {
 	$shellConfig->write_config();
blob - b8ee5dca652b3cbb57b41bc62bc82d032d3441f9
blob + f70c6c921f3dfa9eb0326de299e1b0085ef0aff6
--- lib/IRCNOW/ConfigNow/Module/Prosody.pm
+++ lib/IRCNOW/ConfigNow/Module/Prosody.pm
@@ -12,6 +12,7 @@ sub new {
 		prosody => {
 			filename => "/etc/prosody/prosody.cfg.lua",
 			varlist => [qw{shellname domain}],
+			type => 'shell',
 			template => sub {
 				my $shellname = shift;
 				my $domain = shift;
@@ -27,6 +28,7 @@ ssl = {
 		dns => {
 			filename => "/var/nsd/zones/master/$domain",
 			varlist => [qw(shellname shellname)],
+			type => 'shell',
 			template => qq{
 _xmpp-client._tcp.%s	3600	IN		SRV		0   5   5222     xmpp
 _xmpp-server._tcp.%s	3600	IN		SRV		0   5   5269     xmpp
blob - 78acf3dd7cdbe0e6862e5411ed3c1d4542295b4e
blob + ae759ba2a3e862a95f975afa61fea0a891b938c4
--- lib/IRCNOW/ConfigNow/Module/SmtpDove.pm
+++ lib/IRCNOW/ConfigNow/Module/SmtpDove.pm
@@ -9,9 +9,10 @@ sub new {
 	my $options = {@_};
 	my $domain = $options->{vars}->{domain} || die "{domain} is a reqired option for IRCNOW::ConfigNow::Module::SmtpDove";
 	return $class->SUPER::new( vars => $options->{vars}, files=>{
-		nsd => {
+		dns => {
 			filename => qq{/var/nsd/zones/master/$domain},
 			varlist => ['shellname'],
+			type => 'shell',
 			template => sub {
 				my $shellname = shift;
 				return qq{
@@ -21,41 +22,40 @@ pop.$shellname			3600	IN		CNAME		pop
 pop3.$shellname			3600	IN		CNAME		pop3
 smtp.$shellname			3600	IN		CNAME		smtp
 mail.$shellname			3600	IN		CNAME		mail
-				};
+};
 			},
 		},
 		mail_domains => {
 			filename => qq{/etc/mail/domains},
 			varlist => [qw{shellname domain}],
+			type => 'shell',
 			template => qq{%s.%s\n},
 		},
 		mail_mailname => {
 			filename => qq{/etc/mail/mailname},
 			varlist => [qw{shellname domain}],
+			type => 'shell',
 			template => qq{%s.%s\n},
 		},
 		mail_Virtual => {
 			filename => qq{/etc/mail/virtuals},
 			varlist => [qw{username shellname domain}],
+			type => 'shelluser',
 			template => qq{%s@%s.%s	vmail\n},
 		},
 		mail_user => {
 			filename => qq{/etc/mail/users},
 			varlist => [qw{username shellname domain username shellname domain}],
+			type => 'shelluser',
 			template => qq{%s@%s.%s:	%s@%s.%s\n},
 		},
 		mail_passwd => {
 			filename => qq{/etc/mail/passwd},
 			varlist => [qw{username shellname domain password}],
+			type => 'shelluser',
 			template => qq{%s@%s.%s:%s::::::userdb_quota_rule=*:storage=1G\n},
 		},
 	});
 }
 
-sub create_shell {
-}
-sub create_user {
-}
-
-
 1;
blob - a80dc96608099a5dbf17dc77a5fd79e5c0168644
blob + 6124eb6253aa013fd2c751461cfa9120cb95fb17
--- lib/IRCNOW/ConfigNow/Module.pm
+++ lib/IRCNOW/ConfigNow/Module.pm
@@ -5,10 +5,20 @@ use Carp;
 
 #
 # Each module has a list of files it works with
-# Each file has to have a filename, template, and varlist
-# The template can be a sprintf string or a sub returning a string
-# The varlist will be passed as params to either
-
+# Each file has to have a filename, template, varlist, and type
+#   {filename} filename with path of the system file being modified.
+#              it'll be prefixed with the git repo path.
+#   {template} can be a sprintf string or a sub returning a string
+#    {varlist} is an array of params to pass to sprintf or the sub()
+#              Its an array of param names to be taken from the {vars}
+#              passed from the programs %config.
+#       {type} is used to distinquish between group accounts or sub
+#              accounts of a group.  Each module is expected to have
+#              a primary type and an optional user type. 
+#              eg: shell accounts use 'shell', and 'shelluser'
+#              The 'user' part is hard coded as $type and $type . 'user';
+#			   
+#
 # This can be used as a base class for more advanced or complicated
 # needs or by passing the params needed for a new module to new.
 
@@ -16,8 +26,19 @@ sub new {
 	my $class =shift;
 	my $options = {@_};
 	my $self = {
-		vars => [],
-		files => {},
+		vars => [],				# array ref of data values for template vars.
+		lists => {      		# Hash of lists stored for each module
+			filenames => {		# Hash of filenames
+				# filename => [], #list of files objects using this filename. 
+			},
+		},
+		files => {				#hash of files we can create
+			# file => {
+			# 	filename => /path/to/config/filename,
+			#	template => sub(), or sprintf string
+			#	varlist => []	# list of vars needed to output template
+			#	type => string 	# template type - group/user 
+		},
 	};
 	if (exists $options->{vars}) {
 		$self->{vars}= $options->{vars};
@@ -27,53 +48,89 @@ sub new {
 		for my $file (keys %{$options->{files}}) {
 			# Insure we have the required parms; make a copy of them 
 			#XXX Not sure if a deep copy is needed but loop need to verify the keys.
-			for my $k (qw{filename varlist template}) {
-				croak "Required param $k missing" unless exists $options->{files}->{$file}->{$k};
+			for my $k (qw{filename varlist template type}) {
+				croak "Required param $k missing for Module $class; file: $file" unless exists $options->{files}->{$file}->{$k};
+			
 				$self->{files}->{$file}->{$k} = $options->{files}->{$file}->{$k};
 			}
+			# build a hash of filenames manipulated
+			$self->{files}->{$file}->{filename} =~ s/^\/?//;  # remove leading / if it exists
+			my $filename = $self->{files}->{$file}->{filename};
+			$self->{lists}->{filenames}->{ $filename  } = $self->{files}->{$file};
 		}
 		return $self;
 	}
 	croak "Required list of files to manipulate is missing";
 }
 
+# 
+
 sub list {
 	my $self = shift;
-	my @list = keys(%{$self->{files}});
+	my $type = shift;
+	my @list;
+	for my $file (keys(%{$self->{files}})) {
+		if (defined $type and exists $self->{files}->{type}) {
+			next unless ($self->{files}->{$file}->{type} eq $type);
+		}
+		push @list, $file;
+	}
 	return @list;
 }
 
+#sub files {
+#	my $self = shift;
+#	return keys %{$self->{files}};
+#}
+
+sub filenames {
+	my $self = shift;
+	my @filenames;
+	for my $file (keys  %{$self->{files}} ) {
+		push @filenames, $self->{files}->{$file}->{filename};
+	}
+	return @filenames;
+}
+
 sub filename {
 	my $self = shift;
 	my $file = shift;
 	return $self->{files}->{$file}->{filename};
 }
 
+
+# returns output for filename
 sub output {
 	my $self = shift;
-	my $file = shift || carp "File name required";
+	my $filename = shift || carp "Filename Required";
+	my $type = shift;
 	my @params;
-	# Specified file doesn't exist in this module
-	return unless (
-			exists $self->{files}->{$file} and
-			# Shouldn't have $file without {$file}->{template}
-			#XXX should track down where it's being defined into existance
-			exists $self->{files}->{$file}->{template}
-	);
-	my $mod = $self->{files}->{$file};
 
-	for my $param ( @{$mod->{varlist}}) {
-		# Don't have needed param so return undef
-		unless (defined $self->{vars}->{$param}) {
-			return undef;
+	#	# Specified file doesn't exist in this module
+	#	return unless (
+	#			exists $self->{files}->{$file} and
+	#			# Shouldn't have $file without {$file}->{template}
+	#			#XXX should track down where it's being defined into existance
+	#			exists $self->{files}->{$file}->{template}
+	#	);
+	my $mod = $self->{lists}->{filenames}->{$filename};
+	# If we have a type value then limit output to type specified.
+	# Default to outputting all if not defined.
+	#warn "Module::output() Filename: $filename \$type=$type - \$mod->{type} = ".$mod->{type};
+	if (not defined $type or ($type eq $mod->{type})) {
+		for my $param ( @{$mod->{varlist}}) {
+			# Don't have needed param so return undef
+			unless (exists $self->{vars}->{$param}) {
+				return undef;
+			}
+			push @params, $self->{vars}->{$param};
 		}
-		push @params, $self->{vars}->{$param};
+		if (ref $mod->{template} eq 'CODE') {
+			return $mod->{template}->(@params);
+		}
+		return sprintf($mod->{template}, @params);
 	}
-	if (ref $mod->{template} eq 'CODE') {
-		return $mod->{template}->(@params);
-	}
-
-	return sprintf($mod->{template}, @params);
+	return undef; #nothing to output 
 }
 
 
blob - 6c24bf169e69c41dde01da8fd89c8663cd5a2aee
blob + c3976502956c91a82a41b22ea25efc9f8d448282
--- lib/IRCNOW/ConfigNow.pm
+++ lib/IRCNOW/ConfigNow.pm
@@ -20,9 +20,18 @@ sub new {
 	# set sane defaults. 
 	my $self = {
 		vars =>$options,	# options could be hash template values
+		lists =>{
+				#			users =>[],
+			filenames =>{},	# Hash of filenames containing array of module objects
+			modules =>[],
+		},
 		modules =>{},		# ConfigNow Modules
 		repo =>undef,		# 
 	};
+	my $vars=$self->{vars};
+	# Verify we have critcal
+	$vars->{gitWorkDir} = './configNow' unless exists $vars->{gitWorkDir};
+
 	bless $self, $class;
 	# Load any modules passed in
 	if (exists $options->{modules}) {
@@ -38,63 +47,70 @@ sub new {
 	return $self;
 }
 
-
-sub filename {
+sub filenames {
 	my $self = shift;
-	my $file = shift;
-	my $root = $self->{vars}->{configNow} || './configNow';
-	for my $mod	(keys %{$self->{modules}}) {
-		my $filename = $self->{modules}->{$mod}->filename($file);
-		return $root . $filename if defined $filename;
-	}
+	return keys %{$self->{lists}->{filenames}};
 }
 
 sub list {
 	my $self = shift;
 	my $module = shift;
+	my $type = shift;
 	my @list;
-
+	
 	if (defined $module and exists $self->{modules}->{$module}) {
-		@list = $self->{modules}->{$module}->list();
-
+		@list = $self->{modules}->{$module}->list($type);
 	} else {
 	    @list = keys %{$self->{modules}};
 	}
 	return @list;
 }
 
-sub output {
-	my $self = shift;
-	my $file = shift || carp "!!!!!!!!!!!  undef for file:";
-	my $output = "";
-	for my $mod	(keys %{$self->{modules}}) {
-		$output .= $self->{modules}->{$mod}->output($file) || "";
-	}
+#sub output {
+#	my $self = shift;
+#	my $filename = shift || die "!!!!!!!!!!!  undef for filename:";
+#	my $output = "";
+#	# call each modules output()
+#	for my $filename 
+#	for my $mod	(keys %{$self->{modules}}) {
+#		next unless exists $self->{modules}->{$mod}->{$file};	
+#		$output .= $self->{modules}->{$mod}->output($file) || "";
+#	}
+#	return $output;
+#}
 
-	return $output;
-}
 
-
 sub mod_load {
 	my $self=shift;
 	my $modName=shift;
 	my $module=shift;
+	my $obj;
 	if (ref $module and $module.isa('IRCNOW::ConfigNow::Module')) {
 		# Already have an object so attach it.
 		$self->{modules}->{$modName}=$module;
+		$obj = $module;
 	} else {
 		# Lets assume they passed us a full module name.
 		if (not defined eval "require $module") {
+			warn $module . " - " . $@;
 			# Failed so try prepending IRCNOW::ConfigNow::
 			$module = "IRCNOW::ConfigNow::$module";
 			if (not defined eval "require $module") {
 				croak "Failed to load $module";
 			}
 		}
+		# create module object and add to hash
+		$obj = $module->new(vars => $self->{vars}) || croak 'Failed to load Module: $module';
+		$self->{modules}->{$modName}=$obj;
 	}
-	# create module object and add to hash
-	my $obj = $module->new(vars => $self->{vars}) || croak 'Failed to load Module: $module';
-	$self->{modules}->{$modName}=$obj;
+	# add to loaded modules list.
+	push @{$self->{lists}->{modules}}, $modName;
+	# Build hash of filenames pointing to array of module objects
+	my $filenameList=$self->{lists}->{filenames};
+	for my $filename ($obj->filenames()) {
+		$filenameList->{$filename} = [] unless exists $filenameList->{$filename};
+		push @{$filenameList->{$filename}}, $obj;
+	}
 	return $obj;
 }
 
@@ -107,26 +123,79 @@ sub vars {
 	}
 }
 
+sub write_file {
+	my $self = shift;
+	my $filename = shift;
+	my $workDir=$self->{vars}->{gitWorkDir};
+	$filename = "$workDir/$filename";
+	my $output = shift;
+	my $path = dirname($filename);
+#print "Making Directory: $path\n";
+	make_path($path);
+print "Writing: $filename\n";
+	#XXX add proper error handling
+	open my $FH, ">>$filename";
+	print $FH $output;
+	close $FH;
+}
 
+# Delete specified file
+sub delete_file {
+	my $self = shift;
+	my $filename = shift;
+	my $workDir=$self->{vars}->{gitWorkDir};
+	$filename = "$workDir/$filename";
+print "Deleting $filename\n";
+	unlink $filename;
+	#	unlink $filename;
+	#unlink $self->{modules}->{$module}->filename($file);
+}
+
 sub write_config {
-	my $self=shift;
+	my $self = shift;
+	my $type = $self->{vars}->{type};
+	# abort of the repo isn't ready
 	return 0 unless $self->repo_ready();
-	for my $module ($self->list()) {
-		for my $file ($self->list($module)) {
-			my $filename = $self->filename($file);
-			my $path = dirname($filename);
-			print "Making Directory: $path\n";
-			make_path($path);
-			print "Writing: $filename\n";
-			#XXX add proper error handling
-			open my $FH, ">>$filename";
-			print $FH $self->output($file);
-			close $FH;
+	# get the output for each module for this filename.
+	for my $filename ($self->filenames()) {
+		#purge existing files before generation.
+		$self->delete_file($filename);
+		my $output="";
+		# Output for main type. 
+		for my $obj (@{$self->{lists}->{filenames}->{$filename}}) {
+			my $out = $obj->output($filename,$type);
+			$output .= $out if defined $out;
+			# Output for $type . "users" if we have a user list
+			if (exists $self->{vars}->{users}) {
+				for my $user (@{$self->{vars}->{users}}) {
+					# set the username var to this user.	
+					$self->{vars}->{username} = $user;
+					# generate output for $type . 'user'
+					my $out = $obj->output($filename,$type . "user");
+					$output .= $out if defined $out;
+					# delete the username so it doesn't bleed anywhere
+					delete $self->{vars}->{username};
+				}
+			}
 		}
+		$self->write_file($filename,$output);
 	}
 	return 1;
 }
 
+
+#	or my $module ($self->list()) {
+#		#create the $type root entries. entries.
+#		for my $file ($self->list($module,$type)) {
+#warn "write_config() \$type: $type, \$module: $module, \$file: $file\n";
+#			$self->write_file($file);
+#		}
+#warn "User Loop";
+#		#Create entries for users where needed
+#	}
+#	return 1;
+#}
+
 sub repo_ready {
 	my $self=shift;
 	my $r = $self->{repo};