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 )