Puppet-Classify

 view release on metacpan or  search on metacpan

lib/Puppet/Classify.pm  view on Meta::CPAN





sub remove_group_safe {
    my $self = shift;
    my $name = shift;
    my $force = shift;
    
    my $rule = $self->get_group_rule( $name );
    my $pinned = $self->get_hosts_from_pinned_rule( $rule );
    if( $pinned and @$pinned and not $force ){
        $log->fatal_err( "The group ".$log->quote($name)." has pinned nodes - it can only be removed if you specify (force)" );
    } else {
        $self->try_remove_group( $name, $force );
    }
}







sub try_remove_group {
    my $self = shift;
    my $name = shift;
    my $force = shift;
    my $gid = $self->get_group_id( $name );
    if( not $gid ) { 
        $log->info_msg( $log->quote($name)." doesn't exist - nothing to delete" );
        return;
    }
    my $children = $self->get_group_children( $gid );
    if( @$children ){
        $log->fatal_err( "The group ".$log->quote($name)." has children - it cannot be removed even if you specify (force)" );
    } else {
        $log->info_msg( "Deleting ".$log->quote($name)." as 'force' was specified" ) if $force;
        $log->info_msg( "Deleting ".$log->quote($name)." as 'remove_group' was invocated directly" ) if not $force;
        $self->delete_group( $gid );
        return 1;
    }
}







sub delete_group {
    my $self = shift;
    my $id = shift;
    
    my %headers;
    my $uri = "https://".$self->server_name.":".$self->server_port."/classifier-api/v1/groups/$id";

    my $ssl_opts = { verify_hostname => 1, SSL_ca_file => $self->puppet_ssl_path."/certs/ca.pem" };
    if( $self->cert_name ){
        $ssl_opts->{SSL_cert_file} = $self->puppet_ssl_path."/certs/".$self->cert_name.".pem";
        $ssl_opts->{SSL_key_file} = $self->puppet_ssl_path."/private_keys/".$self->cert_name.".pem";
    } else {
        %headers = ( 'X-Authentication' => $self->access_token );
    }

    my $ua = LWP::UserAgent->new( timeout => $self->timeout, ssl_opts => $ssl_opts );
    my $response = $ua->delete( $uri, %headers );
    die $response->status_line."\n".$response->decoded_content if not $response->is_success( 204 );
}







sub convert_rule_for_puppetdb {
    my $self = shift;
    my $rule = shift;
    return $self->push_data( "rules/translate", $rule );
}







sub get_nodes_matching_group {
    my $self = shift;
    my $group_name = shift;
    my $rule = $self->get_group_rule( $group_name );

    $rule = $self->convert_rule_for_puppetdb( $rule );
    $self->puppet_db->refresh( "nodes", $rule );
    my $data = $self->puppet_db->results;

    my $nodes = [];
    for my $node ( @$data ){
        push @$nodes, $node->{certname};
    }

    return $nodes;
    
}







sub get_hosts_from_pinned_rule {
    my $self = shift;
    my $rule = shift;
    return if not $rule;
    my @rule = @$rule;
    my @nodes;
    if( shift( @rule ) eq 'or' ){
        for my $rule ( @rule ) {
            push @nodes, $rule->[2] if( $rule->[0] eq '=' and $rule->[1] eq 'name' );

lib/Puppet/Classify.pm  view on Meta::CPAN

                }
            } else {
                $log->err_msg( $log->quote($node)." will not be added to the group as it is not found in the PuppetDB" );
            }
        }
    }
    # no point continuing if there are no valid hosts to add
    return if @host_matches == 0;

    my $rule;
    if( $old_rule ){
        if( $old_rule->[0] eq 'or' ){
            for my $nhost ( @host_matches ){
                my $found = 0;
                for my $ohost ( @$old_rule ){
                    next if ref($ohost) ne 'ARRAY';
                    if( $nhost->[2] eq $ohost->[2] ){
                        $found = 1;
                    }
                }
                $log->debug_msg( $log->quote($nhost->[2])." was already present, ignoring" ) if $found;
                push @$old_rule, $nhost if not $found;
            }
            $rule = $old_rule;
        } else {
            $rule = [ 'or', $old_rule, @host_matches ];
        }
    } else {
        $rule = [ 'or', @host_matches ];
    }

    $log->info_msg( "Updating the group: ".$log->quote($group) );
    $self->update_group_rule( $gid, $rule );
}

# The following are really only used internally

sub load_access_token {
    my $token_file = $ENV{"HOME"} . "/.puppetlabs/token";
    my $token = '';
    if ( -r $token_file ) {
        open INFILE, "<$token_file" or die $!;
        while( <INFILE> ){
            $token .= $_;
        }
        close INFILE;
    }
    return $token;
}

sub do_web_request {
    my $self = shift;
    my $type = shift;
    my $action = shift;
    my $data = shift;
    my $uri = "https://".$self->server_name.":".$self->server_port."/classifier-api/v1/$action";
    my $req = HTTP::Request->new( $type, $uri );
    my $ssl_opts = { verify_hostname => 1, SSL_ca_file => $self->puppet_ssl_path."/certs/ca.pem" };
    if( $self->cert_name ){
        $ssl_opts->{SSL_cert_file} = $self->puppet_ssl_path."/certs/".$self->cert_name.".pem";
        $ssl_opts->{SSL_key_file} = $self->puppet_ssl_path."/private_keys/".$self->cert_name.".pem";
    } else {
        $req->header( 'X-Authentication' => $self->access_token );
    }
    my $ua = LWP::UserAgent->new( timeout => $self->timeout, ssl_opts => $ssl_opts );
    if( $type eq 'POST' ){
        $data = encode_json( $data ) if ref $data;
        $req->header( 'Content-Type' => 'application/json' );
        $req->content( $data );
    }
    my $response = $ua->request( $req );
    my $output;
    #if ($response->is_success) {
    if ($response->is_redirect( 303 ) or $response->is_success( 201 )) {
        $output =  $response->decoded_content;
    } else {
        die $response->status_line."\n".$response->decoded_content;
    }
    if( $output ){
        return decode_json( $output );
    } else {
        return;
    }
}

sub push_data {
    my $self = shift;
    my $action = shift;
    my $data = shift;
    return $self->do_web_request( 'POST', $action, $data );
}
sub get_data {
    my $self = shift;
    my $action = shift;
    return $self->do_web_request( 'GET', $action );
}
sub get_data_old {
    my $self = shift;
    my $action = shift;
    my $uri = "https://".$self->server_name.":".$self->server_port."/classifier-api/v1/$action";
    my $req = HTTP::Request->new( 'GET', $uri );
    my $ssl_opts = { verify_hostname => 1, SSL_ca_file => $self->puppet_ssl_path."/certs/ca.pem" };
    if( $self->has_cert_name ){
        $ssl_opts->{SSL_cert_file} = $self->puppet_ssl_path."/certs/".$self->cert_name.".pem";
        $ssl_opts->{SSL_key_file} = $self->puppet_ssl_path."/private_keys/".$self->cert_name.".pem";
    } else {
        $req->header( 'X-Authentication' => $self->access_token );
    }
    my $ua = LWP::UserAgent->new( timeout => $self->timeout, ssl_opts => $ssl_opts );
    my $response = $ua->request( $req );
    my $output;
    if ($response->is_success) {
        $output =  $response->decoded_content;
    } else {
        die $response->status_line."\n".$response->decoded_content;
    }

    my $data  = decode_json( $output );
    return $data;
}

sub push_data_old {
    my $self = shift;
    my $action = shift;
    my $data = shift;
    $data = encode_json( $data ) if ref $data;
    my $uri = "https://".$self->server_name.":".$self->server_port."/classifier-api/v1/$action";
    my $req = HTTP::Request->new( 'POST', $uri );
    my $ssl_opts = { verify_hostname => 1, SSL_ca_file => $self->puppet_ssl_path."/certs/ca.pem" };
    if( $self->has_cert_name ){
        $ssl_opts->{SSL_cert_file} = $self->puppet_ssl_path."/certs/".$self->cert_name.".pem";
        $ssl_opts->{SSL_key_file} = $self->puppet_ssl_path."/private_keys/".$self->cert_name.".pem";
    } else {
        $req->header( 'X-Authentication' => $self->access_token );
    }
    my $ua = LWP::UserAgent->new( timeout => $self->timeout, ssl_opts => $ssl_opts );
    $req->header( 'Content-Type' => 'application/json' );
    $req->content( $data );
    my $response = $ua->request( $req ); 
    my $output;
    if ($response->is_redirect( 303 ) or $response->is_success( 201 )) {
        $output =  $response->decoded_content;
    } else {
        die $response->status_line ."\n".$response->decoded_content;
    }
    if( $output ){
        return decode_json( $output );
    } else {
        return;
    }
}


1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Puppet::Classify - Connects to the Puppet Classifier API (PE Console groups)

=head1 VERSION

version 0.003

=head1 SYNOPSIS

This module interacts with the Puppet Classifier API (i.e. Puppet Enterprise Console Classification groups)

    use Puppet::Classify;

    # Create a Puppet classification object
    my $classify = Puppet::Classify->new( 
                                          cert_name       => $config->{puppet_classify_cert},
                                          server_name     => $config->{puppet_classify_host},
                                          server_port     => $config->{puppet_classify_port},
                                          puppet_ssl_path => $config->{puppet_ssl_path},
                                          puppet_db       => $puppet_db,
                                        );
    # Get a group's rule
    my $rule = $classify->get_group_rule( $group_name );

    # Convert the rule for use with the PuppetDB
    $rule = $classify->convert_rule_for_puppetdb( $rule );

It requires the I<Puppet::DB> module.

=head1 METHODS



( run in 1.967 second using v1.01-cache-2.11-cpan-13bb782fe5a )