diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2018-07-08 22:16:49 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2018-07-08 22:16:49 +0300 |
commit | 69ff9c1766ed89edf0ffdb63bf487396b6bd081b (patch) | |
tree | ef644a810f50d81d3b4e47d7cdbf64df976d8be6 /lib/Config | |
parent | 32b6c6394dc6a789826bd51575d9703bb4097f70 (diff) | |
download | config-haproxy-69ff9c1766ed89edf0ffdb63bf487396b6bd081b.tar.gz config-haproxy-69ff9c1766ed89edf0ffdb63bf487396b6bd081b.tar.bz2 |
Add documentationv1.00
Diffstat (limited to 'lib/Config')
-rw-r--r-- | lib/Config/HAProxy.pm | 140 | ||||
-rw-r--r-- | lib/Config/HAProxy/Iterator.pm | 68 | ||||
-rw-r--r-- | lib/Config/HAProxy/Node.pm | 137 | ||||
-rw-r--r-- | lib/Config/HAProxy/Node/Comment.pm | 31 | ||||
-rw-r--r-- | lib/Config/HAProxy/Node/Empty.pm | 29 | ||||
-rw-r--r-- | lib/Config/HAProxy/Node/Root.pm | 52 | ||||
-rw-r--r-- | lib/Config/HAProxy/Node/Section.pm | 153 | ||||
-rw-r--r-- | lib/Config/HAProxy/Node/Statement.pm | 45 |
8 files changed, 628 insertions, 27 deletions
diff --git a/lib/Config/HAProxy.pm b/lib/Config/HAProxy.pm index 7938bcb..f99bf33 100644 --- a/lib/Config/HAProxy.pm +++ b/lib/Config/HAProxy.pm @@ -182,10 +182,10 @@ sub save { $self->backup; rename($tempfile, $self->filename) or croak "can't rename $tempfile to ".$self->tempfile.": $!"; - # This will fail unless we are root, let it be so. - chown $sb->uid, $sb->gid, $self->filename; # This will succeed: we've created the file, so we're owning it. chmod $sb->mode & 0777, $self->filename; + # This will fail unless we are root, let it be so. + chown $sb->uid, $sb->gid, $self->filename; $self->tree->clear_dirty } @@ -215,39 +215,90 @@ __END__ =head1 NAME -Config::HAProxy - HAProxy configuration file +Config::HAProxy - Parser for HAProxy configuration file =head1 SYNOPSIS -use Config::HAProxy; -$cfg = new Config::HAProxy($filename); -$cfg->parse; + use Config::HAProxy; + $cfg = new Config::HAProxy($filename); + $cfg->parse; -$name = $cfg->filename; + $name = $cfg->filename; -@frontends = $cfg->select(name => 'frontend'); + @frontends = $cfg->select(name => 'frontend'); -$itr = $cfg->iterator(inorder => 1); -while (defined($node = $itr->next)) { - # do something with $node -} + $itr = $cfg->iterator(inorder => 1); + while (defined($node = $itr->next)) { + # do something with $node + } -$cfg->save; + $cfg->save; -$cfg->write($file_or_handle); + $cfg->write($file_or_handle); -$cfg->backup; -$name = $self->backup_name; + $cfg->backup; + $name = $self->backup_name; -$cfg->reset; -$cfg->push($node); -$node = $cfg->pop; -$node = $cfg->tos; -$node = $cfg->tree; + $cfg->reset; + $cfg->push($node); + $node = $cfg->pop; + $node = $cfg->tos; + $node = $cfg->tree; =head1 DESCRIPTION -FIXME +The B<Config::HAProxy> class is a parser that converts the B<HAProxy> +configuration file to a parse tree and provides methods for various +operations on this tree, such as: searching, modifying and saving it +to a file. + +An object of this class contains a I<parse tree> representing the +configuration read from the file (or created from scratch). Nodes in the +tree can be of four distinct classes: + +=over 4 + +=item Empty + +Represents an empty line. + +=item Comment + +Represents a comment line. + +=item Statement + +Represents a simple statement. + +=item Section + +A container, representing a C<compound statement>, i.e. a statement that +contains multiple sub-statements. Compound statements are: B<global>, +B<defaults>, B<frontend>, and B<backend>. + +=back + +In addition to these four classes, a special class B<Root> is provided, which +represents the topmost node in the parse tree (i.e. the parent of other nodes). + +A set of attributes is associated with each node. Among these, the B<orig> +attribute contains the original line from the configuration file that triggered +creation of this node, and B<locus> contains the location of this line (or +lines, for sections) in the configuration file (as a B<Text::Locus>) object. + +These two attributes are meaningful for all nodes. For statement nodes (simple +statements and sections) the B<kw> attribute contains the statement I<keyword>, +and the B<argv> attribute - its arguments. For example, the statement + + server localhost 127.0.0.1:8080 + +is represented by a node of class B<Config::HAProxy::Node::Statement>, with +C<server> as B<kw> and list (C<localhost>, C<127.0.0.1:8080>) as B<argv>. + +Additionally, section nodes provide methods for accessing their subtrees. + +For a detailed description of the node class and its methods, please refer to +B<Config::HAProxy::Node>. =head1 CONSTRUCTOR @@ -257,15 +308,23 @@ Creates and returns a new object for manipulating the HAProxy configuration. Optional B<$filename> specifies the name of the file to read configuration from. It defaults to F</etc/haproxy/haproxy.cfg>. -=head1 THE PARSE TREE +=head2 filename + + $s = $cfg->filename; + +Returns the configuration file name given when creating the object. + +=head1 PARSING =head2 parse $cfg->parse; Reads and parses the configuration file. Croaks if the file does not exist. +Returns B<$cfg>. - +=head1 BUILDING THE PARSE TREE + =head2 reset $cfg->reset; @@ -305,7 +364,7 @@ Returns the last node in the tree. $cfg->save; -Saves the configuration file. +Saves the parse tree in the configuration file. =head2 write @@ -327,3 +386,34 @@ Normally, comments retain their original indentation. However, if the key B<reintent_comments> is present, and its value is evaluated as true, then comments are reindented following the rules described above. +=head1 SEE ALSO + +B<Config::HAProxy::Node>, +B<Config::HAProxy::Node::Section>, +B<Config::HAProxy::Node::Statement>, +B<Config::HAProxy::Iterator>. + +=head1 AUTHOR + +Sergey Poznyakoff, E<lt>gray@gnu.orgE<gt> + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2018 by Sergey Poznyakoff + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this library. If not, see <http://www.gnu.org/licenses/>. + +=cut + + diff --git a/lib/Config/HAProxy/Iterator.pm b/lib/Config/HAProxy/Iterator.pm index 6b0208e..6d80dd9 100644 --- a/lib/Config/HAProxy/Iterator.pm +++ b/lib/Config/HAProxy/Iterator.pm @@ -63,6 +63,74 @@ sub next { } 1; +__END__ + +=head1 NAME + +Config::HAProxy::Iterator - Iterate over objects in the parse tree + +=head1 SYNOPSIS + + $cfg = Config::HAProxy->new->parse; + $itr = $cfg->iterator(inorder => 1); + while (defined(my $node = $itr->next)) { + # Do something with $node + } + +=head1 DESCRIPTION + +The iterator object provides a method for iterating over all nodes in the +HAProxy parse tree. The object is returned by the B<iterator> method of +B<Config::HAProxy> and B<Config::HAProxy::Node> objects. The method takes +as optional argument the keyword specifying the order in which the tree nodes +should be traversed. This keyword can be one of the following: + +=over 4 + +=item B<recursive =E<gt> 0> + +No recursion. The traversal will not descend into section nodes. This is the +default. + +=item B<inorder =E<gt> 1> + +The nodes will be traversed in the inorder manner, i.e. the section node +will be visited first, and all its sub-nodes after it. + +=item B<postorder =E<gt> 1> + +The nodes will be traversed in the postorder manner, i.e. for each section +node, its sub-nodes will be visited first, and the node itself afterward. + +=back + +=head1 CONSTRUCTOR + +Note: This section is informative. You never need to create +B<Config::HAProxy::Iterator> objects explicitly. Please use the B<iterator> +method of B<Config::HAProxy> or B<Config::HAProxy::Node> class objects. + + $itr = new Config::HAProxy::Iterator($node, %rec); + +Returns new iterator object for traversing the tree starting from B<$node>, +which must be a B<Config::HAProxy::Node> object. Optional B<%rec> is one of +the keywords discussed above, in section B<DESCRIPTION>. + +=head1 METHODS + +=head2 next + + $node = $itr->next; + +Returns next node in the traversal sequence. If all nodes were visited, returns +B<undef>. + +=head1 SEE ALSO + +B<HAProxy::Config>, B<HAProxy::Config::Node>. + +=cut + diff --git a/lib/Config/HAProxy/Node.pm b/lib/Config/HAProxy/Node.pm index be09538..8210067 100644 --- a/lib/Config/HAProxy/Node.pm +++ b/lib/Config/HAProxy/Node.pm @@ -97,3 +97,140 @@ sub is_empty { 0 } sub is_comment { 0 } 1; +__END__ + +=head1 NAME + +Config::HAProxy::Node - Abstract HAProxy configuration node + +=head1 DESCRIPTION + +The class B<Config::HAProxy::Node> represents an abstract node in the +HAProxy configuration parse tree. It serves as a base class for classes +representing configuration tree, section, simple statement, comment and +empty line. + +=head1 CONSTRUCTOR + + $obj = new Config::HAProxy::Node(%args); + +Returns new object. B<%args> can contain the following keys: + +=over 4 + +=item B<kw> + +Configuration keyword (string), + +=item B<argv> + +Reference to the list of arguments. + +=item B<orig> + +Original text as read from the configuration file. + +=item B<locus> + +Locus (a B<Text::Locus> object) where this statement occurred. + +=item B<parent> + +Parent node. + +=back + +=head1 METHODS + +=head2 B<kw>, B<argv>, B<orig>, B<locus>, B<parent> + +These methods return the corresponding field of the node. When called +with an argument, they set the field prior to returning it. The B<argv> +method returns array of strings and takes as its argument a reference to +the array of strings: + + @a = $node->argv; + + $node->argv([@a]); + +=head2 index + +Index (0-based) of this node in the parent node. + +=head2 arg + + $a = $node->arg($n) + +Returns the B<$n>th argument (0-based) from the argument list. + +=head2 drop + + $node->drop; + +Removes this node and destroys it. + +=head2 iterator + + $itr = $node->iterator(@args); + +Returns the iterator for this node. See B<Config::HAProxy::Iterator> for +a detailed discussion. + +=head2 depth + + $n = $node->depth; + +Returns the depth of this node in the configuration tree. Depth is the +number of parent nodes between the root of tree and this node. Top-level +nodes have depth 0. + +=head2 root + + $root_node = $node->root; + +Returns the root node of the parse tree this node belongs to. + +=head2 as_string + + $s = $node->as_string; + +Returns canonical string representation of this node. The canonical +representation consists of the keyword followed by arguments delimited +with horizontal space characters. + +=head1 ABSTRACT METHODS + +Derived classes must overload at least one of the following methods: + +=head2 is_root + +True if the node is a root node, false otherwise. + +=head2 is_section + +True if the node represents a section (i.e. contains subnodes). + +=head2 is_statement + +True if the node is a simple statement. + +=head2 is_empty + +True if the node represents an empty line. + +=head2 is_comment + +True if the node represents a comment. + +=head1 SEE ALSO + +B<Config::HAProxy::Node::Comment>, +B<Config::HAProxy::Node::Empty>, +B<Config::HAProxy::Node::Root>, +B<Config::HAProxy::Node::Section>, +B<Config::HAProxy::Node::Statement>, +B<Config::HAProxy::Iterator>, +B<Config::HAProxy>, +B<Text::Locus>. + +=cut diff --git a/lib/Config/HAProxy/Node/Comment.pm b/lib/Config/HAProxy/Node/Comment.pm index 5d7ef88..17a513b 100644 --- a/lib/Config/HAProxy/Node/Comment.pm +++ b/lib/Config/HAProxy/Node/Comment.pm @@ -1,6 +1,37 @@ package Config::HAProxy::Node::Comment; use parent 'Config::HAProxy::Node'; +=head1 NAME + +Config::HAProxy::Node::Comment - comment node in HAProxy configuration + +=head1 DESCRIPTION + +Objects of this class represent comments in HAProxy configuration file. + +=head1 METHODS + +=head2 is_comment + +Returns true. + +=head2 orig + +Returns original line as it appeared in the configuration file. + +=head2 locus + +Returns the location of this statement in the configuration file (the +B<Text::Locus> object). + +=head1 SEE ALSO + +B<Config::HAProxy::Node>, B<Text::Locus>. + +=cut + sub is_comment { 1 } 1; + + diff --git a/lib/Config/HAProxy/Node/Empty.pm b/lib/Config/HAProxy/Node/Empty.pm index bee0f2e..19ce5da 100644 --- a/lib/Config/HAProxy/Node/Empty.pm +++ b/lib/Config/HAProxy/Node/Empty.pm @@ -1,6 +1,35 @@ package Config::HAProxy::Node::Empty; use parent 'Config::HAProxy::Node'; +=head1 NAME + +Config::HAProxy::Node::Empty - empty HAProxy configuration node + +=head1 DESCRIPTION + +Objects of this class represent empty lines in HAProxy configuration file. + +=head1 METHODS + +=head2 is_empty + +Always true. + +=head2 orig + +Returns original line as it appeared in the configuration file. + +=head2 locus + +Returns the location of this statement in the configuration file (the +B<Text::Locus> object). + +=head1 SEE ALSO + +B<Config::HAProxy::Node>, B<Text::Locus>. + +=cut + sub is_empty { 1 } 1; diff --git a/lib/Config/HAProxy/Node/Root.pm b/lib/Config/HAProxy/Node/Root.pm index 656bb9f..ca6e575 100644 --- a/lib/Config/HAProxy/Node/Root.pm +++ b/lib/Config/HAProxy/Node/Root.pm @@ -4,6 +4,19 @@ use warnings; use parent 'Config::HAProxy::Node::Section'; use Carp; +=head1 NAME + +Config::HAProxy::Node::Root - root node of HAProxy configuration parse tree + +=head1 DESCRIPTION + +Objects of this class represent the topmost node in HAProxy configuration tree. +Each parse tree contains exactly one object of this class. This node can be +reached from every node in the tree by following its B<parent> attribute +and is returned by the B<tree> method of B<Config::HAProxy> class. + +=cut + sub new { my $class = shift; my $self = $class->SUPER::new(@_); @@ -11,21 +24,58 @@ sub new { return $self; } +=head1 METHODS + +=head2 is_root + +Always true. + +=head2 is_dirty + + $bool = $node->is_dirty; + +Returns true if the tree is C<dirty>, i.e. it was modified since it has been +created from the disk configuration file. + +=cut + sub is_dirty { my $self = shift; return $self->{dirty} } +=head2 mark_dirty + + $node->mark_dirty; + +Sets the C<dirty> attribute. + +=cut + sub mark_dirty { my $self = shift; $self->{dirty} = 1; } +=head2 clear_dirty + + $node->clear_dirty; + +Clears the C<dirty> attribute. + +=cut + sub clear_dirty { my $self = shift; $self->{dirty} = 0; } - + +=head1 SEE ALSO + +B<Config::HAProxy::Node>. + +=cut + 1; diff --git a/lib/Config/HAProxy/Node/Section.pm b/lib/Config/HAProxy/Node/Section.pm index c332155..3ef1cf0 100644 --- a/lib/Config/HAProxy/Node/Section.pm +++ b/lib/Config/HAProxy/Node/Section.pm @@ -4,6 +4,18 @@ use warnings; use parent 'Config::HAProxy::Node'; use Carp; +=head1 NAME + +Config::HAProxy::Node::Section - HAProxy configuration section + +=head1 DESCRIPTION + +Objects of this class represent a C<section> in the HAProxy configuration file. +A section is a statement that can contain sub-statements. The following +statements form sections: B<global>, B<defaults>, B<frontend>, and B<backend>. + +=cut + sub new { my $class = shift; my $self = $class->SUPER::new(@_); @@ -11,8 +23,51 @@ sub new { return $self; } +=head1 ATTRIBUTES + +=head2 is_section + +Always true. + +=cut + sub is_section { 1 } +=head1 METHODS + +=head2 kw + +Returns the configuration keyword. + +=head2 argv + +Returns the list of arguments to the configuration keyword. + +=head2 arg + + $s = $node->arg($n) + +Returns the B<$n>th argument. + +=head2 orig + +Returns original line as it appeared in the configuration file. + +=head2 locus + +Returns the location of this statement in the configuration file (the +B<Text::Locus> object). + +=head2 append_node + + $section->append_node(@nodes); + +Takes a list of objects of B<Config::HAProxy::Node> derived classes as +arguments. Adds these objects after the last node in the subtree in this +section. + +=cut + sub append_node { my $self = shift; my $n = @{$self->{_tree}}; @@ -24,6 +79,15 @@ sub append_node { } @_; } +=head2 append_node_nonempty + + $section->append_node_nonempty(@nodes); + +Same as B<append_node>, but adds new nodes after the last non-empty +node in the subtree. + +=cut + sub append_node_nonempty { my $self = shift; my $n = $#{$self->{_tree}}; @@ -32,7 +96,15 @@ sub append_node_nonempty { } $self->insert_node($n+1, @_); } - + +=head2 insert_node + + $section->insert_node($idx, @nodes); + +Inserts B<@nodes> after subnode in position B<$idx> (0-based). + +=cut + sub insert_node { my $self = shift; my $n = shift; @@ -48,6 +120,14 @@ sub insert_node { } } +=head2 delete_node + + $section->delete_node($i); + +Deletes B<$i>th subnode from the B<$section>. + +=cut + sub delete_node { my ($self, $n) = @_; splice @{$self->{_tree}}, $n, 1; @@ -57,6 +137,18 @@ sub delete_node { $self->root->mark_dirty; } +=head2 tree + + @nodes = $section->tree; + +Returns subnodes as a list of B<Config::HAProxy::Node> derived objects. + + $node = $section->tree($i); + +Returns B<$i>th subnode from the B<$section>. + +=cut + sub tree { my ($self, $n) = @_; if ($n) { @@ -66,6 +158,15 @@ sub tree { return @{shift->{_tree}} }; +=head2 ends_in_empty + + $bool = $section->ends_in_empty + +Returns true if the last node in the list of sub-nodes in B<$section> is +an empty node. + +=cut + sub ends_in_empty { my $self = shift; while ($self->is_section) { @@ -110,6 +211,50 @@ my %match = ( } ); +=head2 select + + @nodes = $section->select(%cond); + +Returns nodes from B<$section> that match conditions in B<%cond>. Valid +conditions are: + +=over 4 + +=item B<name =E<gt>> I<$s> + +Node matches if its keyword (B<kw>) equals I<$s>. + +=item B<arg =E<gt>> B<{ n =E<gt>> I<$n>, B<v> =E<gt> I<$s> B<}> + +Node mathches if its I<$n>th argument equals I<$s>. + +=item B<section =E<gt>> I<$bool> + +Node matches if it is (or is not, if I<$bool> is false) a section. + +=item B<statement =E<gt>> I<$bool> + +Node matches if it is (not) a simple statement. + +=item B<comment =E<gt>> I<$bool> + +Node matches if it is (not) a comment. + +=back + +Multiple conditions are checked in the order of their appearance in the +argument list and are joined by the short-circuit logical C<and>. + +For example, to return all B<frontend> statements: + + @fe = $section->select(name => 'frontend'); + +To return the frontend named C<in>: + + ($fe) = $section->select( name => 'frontend', + arg => { n => 0, v => 'in' } ); + +=cut sub select { my $self = shift; @@ -138,6 +283,12 @@ sub _test_node { return 1; } +=head1 SEE ALSO + +B<Config::HAProxy::Node>, B<Config::HAProxy>, B<Text::Locus>. + +=cut + 1; diff --git a/lib/Config/HAProxy/Node/Statement.pm b/lib/Config/HAProxy/Node/Statement.pm index abf0e50..305c529 100644 --- a/lib/Config/HAProxy/Node/Statement.pm +++ b/lib/Config/HAProxy/Node/Statement.pm @@ -1,6 +1,51 @@ package Config::HAProxy::Node::Statement; use parent 'Config::HAProxy::Node'; +=head1 NAME + +Config::HAProxy::Node::Statement - simple statement node in HAProxy tree + +=head1 DESCRIPTION + +Objects of this class represent simple statements in HAProxy configuration +file. A C<simple statement> is any statement excepting: B<global>, B<defaults>, +B<frontend>, and B<backend>. + +=head1 METHODS + +=head2 is_statement + +Returns true. + +=head2 kw + +Returns the configuration keyword. + +=head2 argv + +Returns the list of arguments to the configuration keyword. + +=head2 arg + + $s = $node->arg($n) + +Returns the B<$n>th argument. + +=head2 orig + +Returns original line as it appeared in the configuration file. + +=head2 locus + +Returns the location of this statement in the configuration file (the +B<Text::Locus> object). + +=head1 SEE ALSO + +B<Config::HAProxy::Node>, B<Config::HAProxy>, B<Text::Locus>. + +=cut + sub is_statement { 1 } 1; |