# NAME

Puppet::DB - Object for easily getting Puppet DB data (e.g. facts, reports, etc)

# VERSION

version 0.001

# SYNOPSIS

This module provides methods to make it easy to connect to the Puppet DB and to put the data into a form where it can
be manipulated more readily.

It can extract anything from the Puppet DB that is supported by the API.  See the Puppet docs for more information on
the API: [https://puppet.com/docs/puppetdb/latest/api/index.html](https://puppet.com/docs/puppetdb/latest/api/index.html).  Although this module tries to make it easier and 
more approachable by abstracting away some complexity, it still requires a basic understanding of how the API works.  
There is a bunch of Perl scripts I have created that consumes this and other Puppet Perl modules I have written. They 
provide some examples of what can be done.  They are distributed in a Puppet module as they are generally only 
useful in a Puppet environment. Consequently the best way to install them is via the module.  The module can be found 
here: [https://github.com/Q-Technologies/puppet-utility\_scripts](https://github.com/Q-Technologies/puppet-utility_scripts).

Here is an example of how to use `Puppet::DB`:

    use Puppet::DB;

    my $puppet_db = Puppet::DB->new;

    $puppet_db->refresh_facts;
    my $facts = $puppet_db->allfacts_by_certname;

    say $facts->{testhost.example.com}{osfamily};

Would output `Suse` if there was a SLES system called `testhost.example.com`

The AST query system of the Puppet DB is supported: [https://puppet.com/docs/puppetdb/latest/api/query/v4/ast.html](https://puppet.com/docs/puppetdb/latest/api/query/v4/ast.html).
Rather than specifying it in JSON, specify it as Perl data structures. This module will convert it to JSON when it
communicates with the Puppet DB.  Some sample queries:

     use Puppet::DB;
     use Data::Dumper;

     my $mode = "facts";
     my $fact = 'osfamily';
     my $value = 'RedHat';
     my $rule = { 'query'    => [ "and", ["=","name", $fact], 
                                         ["~", "value", $value ] ], 
                  "order_by" => [{"field" => "certname"}] };
    
     my $puppet_db = Puppet::DB->new;
     $puppet_db->refresh($mode, $rule);
     print Dumper( $puppet_db->results );

     my $fact = 'os.family';
     $mode = "fact-contents";
     $rule = { 'query'    => [ "and", ["=","path", [split( /\./, $fact)] ], 
                                      ["~", "value", $value ] ], 
               "order_by" => [{"field" => "certname"}] };
     $puppet_db->refresh($mode, $rule);
     print Dumper( $puppet_db->results );

The second example demonstrates how to search via a complex fact.

This is how to access the reports:

    $rule = ['=', 'job_id', $opt_j ];
    $puppet_db->refresh( "reports", $rule );
    print Dumper( $puppet_db->results );

    $node_rule = ['=', 'certname', 'testhost.example.com' ];
    $rule = [ 'and', ['=', 'latest_report?', 'true' ],
                     $node_rule,
            ];
    $puppet_db->refresh( "reports", $rule );
    print Dumper( $puppet_db->results );

# METHODS

## new

Create a new `Puppet::DB` object connecting to [http://localhost:8080](http://localhost:8080):

    my $puppet_db = Puppet::DB->new;

or, Connect to a Puppet DB host called [puppet](https://metacpan.org/pod/puppet)

    my $puppet_db = Puppet::DB->new( 'puppet' );

or, connect to a non standard port:

    my $puppet_db = Puppet::DB->new( server_name => 'puppet', server_port => '1234');

### server\_name

If you did not specify the server to connect when the object was created you can set it with this method.
The default value is `localhost`.

    $puppet_db->server_name( 'puppet' );

This can be changed at any time for subsequent queries if you need to connect to another Puppet DB.

### server\_port

If you did not specify the port to connect when the object was created you can set it with this method.
The default value is `8080`.

    $puppet_db->server_port( '1234' );

This can be changed at any time for subsequent queries if you need to connect to another Puppet DB.

## Data Loading Methods

### refresh

This method needs to be called to populate the `Puppet::DB` object with data from the Puppet DB.  This needs to be 
called everytime you change the query.

    $puppet_db->refresh( 'facts' );

or

    my $query = { 'query' => ["~","certname", '.*\.example.com'], "order_by" => [{"field" => "certname"}] };
    $puppet_db->refresh( 'facts', $query );

No data will be returned.  The data can be accessed through one of the accessor methods.

### refresh\_facts

This method can to be called to populate the [Puppet::DB](https://metacpan.org/pod/Puppet::DB) object with facts data from the Puppet DB.  It does the same as `$puppet_db->refresh( 'facts' ); $puppet_db->facts( $puppet_db->results );` - 
i.e. it populates the [facts](https://metacpan.org/pod/facts) property as well as the [results](https://metacpan.org/pod/results) property.

    $puppet_db->refresh_facts; # Load all facts from the Puppet DB (will be slow for a large instance)

or

    my $query = { 'query' => ["~","certname", '.*\.example.com'], "order_by" => [{"field" => "certname"}] };
    $puppet_db->refresh_facts( $query );

No data will be returned.  The data can be accessed through one of the accessor methods.

## Accessor Methods

### results

Return all the results gathered from the last ["refresh"](#refresh) (including anything that calls [refresh](https://metacpan.org/pod/refresh) indirectly - i.e. it can only be trusted if used immediately after calling [refresh](https://metacpan.org/pod/refresh)).

    my $results = $puppet_db->results;

### facts

Return all the facts gathered from the last ["refresh\_facts"](#refresh_facts)

    my $facts = $puppet_db->facts;

This returns the data in the form that the Puppet DB provides it as. The other fact accessor methods manipulate 
it for easier consumption.

### allfacts\_by\_certname

Get all the facts for the specified `certname`.

    $puppet_db->allfacts_by_certname( 'testhost.example.com' );

The facts will be returned as complex data (i.e hash ref).

### allfacts\_by\_hostname

Get all the facts for the specified `hostname`.

    $puppet_db->allfacts_by_hostname( 'testhost.example.com' );

The facts will be returned as complex data (i.e hash ref).

_Note_ that it will match the last `hostname` found by looking at the first field in the `certname`.  Basically, 
if you have two nodes with a different `certname`, but the same hostname, you may not get the intended host.  If 
this is a risk, then always use the `certname`.

### get\_fact

This will return a fact value matching the specified `certname` and `fact`.  It is a shortcut for ["get\_fact\_by\_certname"](#get_fact_by_certname).

    $puppet_db->get_fact( 'testhost.example.com', 'osfamily' );

The fact value may be a string or complex data (i.e hash or array ref).

### get\_fact\_by\_certname

This will return a fact value matching the specified `certname` and `fact`.

    $puppet_db->get_fact_by_certname( 'testhost.example.com', 'osfamily' );

The fact value may be a string or complex data (i.e hash or array ref).

### get\_fact\_by\_short\_hostname

This will return a fact value matching the specified `hostname` and `fact`.  Note that it will match the first `hostname` found by looking at the first field in the `certname`.

    $puppet_db->get_fact_by_short_hostname( 'testhost', 'osfamily' );

The fact value may be a string or complex data (i.e hash or array).

### is\_certname\_in\_puppetdb

This will return true or false based on whether the specified certname can be found in the Puppet DB.

    $puppet_db->is_certname_in_puppetdb( 'testhost.example.com' );

### is\_node\_in\_puppetdb

This will return true or false based on whether the specified node can be found in the Puppet DB.  This is a synonym of ["is\_certname\_in\_puppetdb"](#is_certname_in_puppetdb).

    $puppet_db->is_node_in_puppetdb( 'testhost.example.com' );

### is\_hostname\_in\_puppetdb

This will return the _certname_ if the _hostname_ of a node can be found in the Puppet DB. It will match
the first _certname_ where the first field matches the _hostname_.

    $puppet_db->is_hostname_in_puppetdb( 'testhost' );

If a hostname is provided with dots in it, it will be assumed to be a _certname_ and simply returned back if 
it is found in the PuppetDB.

False (i.e. 0) is returned if it is not found in the PuppetDB.

# FUNCTIONS

## parse\_puppetdb\_time

Puppet DB time is always stored and reported as GM time in a text string.  This method will convert it 
into a [time(2)](http://man.he.net/man2/time) value in seconds since the system epoch (Midnight, January 1, 1970 GMT on Unix).

    my $time = parse_puppetdb_time( '2016-02-08T02:21:04.417Z' );

# BUGS/FEATURES

Please report any bugs or feature requests in the issues section of GitHub: 
[https://github.com/Q-Technologies/perl-Puppet-DB](https://github.com/Q-Technologies/perl-Puppet-DB). Ideally, submit a Pull Request.

# AUTHOR

Matthew Mallard <mqtech@cpan.org>

# COPYRIGHT AND LICENSE

This software is copyright (c) 2019 by Matthew Mallard.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
